atwix

Creating automatic emails for custom events in Magento

Magento is a relatively intelligent system. It implements an Event/Observer pattern for end users to hook into. You can catch different events and process them with your logic after. For example, if you want to perform an action after a user was logged in, you can use customer_login event, for an action implementation after the event.

Also, you can use Event/Observer technology for sending custom emails after an action has taken place.
For example, let’s say we need to send a custom email when a customer’s order has been canceled.
Let see what we can do here.

Step1:

First, you should make your own module. Here is a brief example. If you need more information – feel free reading my previous blogposts.

Create a file /app/etc/modules/Namespace_Custmail.xml with following content:

<?xml version="1.0" encoding="UTF-8"?>
<config>
	<modules>
		<Namespace_Custmail>
			<active>true</active>
			<codePool>community</codePool>
		</Namespace_Custmail>
	</modules>
</config>

Create file /app/code/community/Namespace/Custmail/etc/config.xml with following content:

<config>
    <modules>
        <Namespace_Custmail>
            <version>1.0.0</version>
        </Namespace_Custmail>
    </modules>

    <global>
        <models>
            <custmail>
                <class>Namespace_Custmail</class>
            </custmail>
        </models>
        <events>
            <sales_order_save_commit_after>
                <observers>
                    <mail_status_change>
                        <type>singleton</type>
                        <class>custmail/observer</class>
                        <method>invoicedStatusChange</method>
                    </mail_status_change>
                </observers>
            </sales_order_save_commit_after>
        </events>
        <template>
            <email>
                <custom_order_tpl module="Namespace_Custmail">
                    <label>Status Mail Invoice</label>
                    <file>statusmail_processing.html</file>
                    <type>html</type>
                </custom_order_tpl>
            </email>
        </template>
    </global>
</config>

Step 2:

Now we need to create an observer. If you need more detailed explanation about observers, you can read this article.

Create file /app/code/community/Namespace/Custmail/Model/Observer.php with following content:

class Namespace_Custmail_Model_Observer
{
    public function invoicedStatusChange($event)
    {
        $order = $event->getOrder();
        $orderStatus = $order->getStatus();
		if ($order->getState() == Mage_Sales_Model_Order::STATE_CANCELED)
			$this->_sendStatusMail($order);
    }

    private  function _sendStatusMail($order)
    {
        $emailTemplate  = Mage::getModel('core/email_template');

        $emailTemplate->loadDefault('custom_order_tpl');
		$emailTemplate->setTemplateSubject('Your order was holded');

        // Get General email address (Admin->Configuration->General->Store Email Addresses)
        $salesData['email'] = Mage::getStoreConfig('trans_email/ident_general/email');
        $salesData['name'] = Mage::getStoreConfig('trans_email/ident_general/name');

        $emailTemplate->setSenderName($salesData['name']);
        $emailTemplate->setSenderEmail($salesData['email']);

        $emailTemplateVariables['username']  = $order->getCustomerFirstname() . ' ' . $order->getCustomerLastname();
        $emailTemplateVariables['order_id'] = $order->getIncrementId();
        $emailTemplateVariables['store_name'] = $order->getStoreName();
        $emailTemplateVariables['store_url'] = Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB);
        $emailTemplate->send($order->getCustomerEmail(), $order->getStoreName(), $emailTemplateVariables);
    }
}


Step 3:

Next, create a html/text template for your email. It should be a file
/app/locale/en_US/template/email/statusmail_processing.html
with following content:

<div>
	<h1>Dear {{var username}}</h1>
	<p>Your order #{{var order_id}} was canceled for some reasons… </p>
	<div>{{var storename}} ({{var store_url}})</div>
</div>

You can create the html file in a subfolder with your own name, but you should describe all of this in the template email section config file.
Note that words the ‘Namespace’ and ‘Custmail’ will need to be replaced with ‘YourCompanyName’ and ‘YourModuleName’.

Now, let’s go back to explanations.
We have an observer class Namespace_Custmail_Model_Observer with two methods.
Method invoicedStatusChange calls when an event sales_order_save_commit_after occurred (it was described in our config file in the observer method section). It checks the current order status and if status = ‘Canceled’ the method calls _sendStatusMail.
Method _sendStatusMail generates an email with the necessary data.

We have to fill 4 required parameters:

$emailTemplate->loadDefault(..template file..) – Here ..template file.. is our template’s identifier. We have described it in the config file

<custom_order_tpl>
...
</custom_order_tpl>

$emailTemplate->setTemplateSubject(..subject..) – This is the email subject, make sure you fill it in.

$emailTemplate->setSenderName(..name..), $emailTemplate->setSenderEmail(..email..) – Email fields ‘FROM: ..name.. ..email..

As for the $emailTemplateVariables array, it contains data that we want to store in our template. As you can see from step 3, there are constructions like ‘{{var username}}‘. So, it’s nothing more than value in the $emailTemplateVariables array with index ‘username’. In other words, if you have the value $emailTemplateVariables['my_mothers_name'], you can get this value in the template file with construction {{var my_mothers_name}}. Note: if you want to use your variables in templates, you should add your var as the argument when you call ‘send’ method. $emailTemplate->send($order->getCustomerEmail(), $order->getStoreName(), $emailTemplateVariables) has $emailTemplateVariables (our values set) as the 3rd argument.

You can also send emails in other formats. For example, if you want to send your custom letter in plain text, you should use

<type>text</type>

in the config.xml when describing the template section.

That’s it! Now customers will receive our custom email when their orders get canceled. You can also handle any other magento event with observers and send custom emails to anyone (customer/admin/girlfriend etc..).
Happy coding!



Enjoyed this post? us on Facebook and on Twitter to stay tuned.

  • http://www.expertmagentodevelopers.com Magento Development

    Wow what a post. it is very useful information. i will also share the link with my friends. thanks for sharing.

  • TheStiffCollar

    Hi, Superb tutorial, unfortunately not working for 1.4.2, any ideas?

    • Yaroslav Rogoza

      Can’t say exactly why. Logic should work on magento 1.4+. There may be many nuances with conflicts/cache/precompiler/namespaces and other things. I need to see the code.

  • Yaroslav Rogoza

    Hi. You should create your own magento extension like I’ve described in my article but with your php logic. You will have your event observer which you should use on event ‘sales_order_place_after’ instead of ‘sales_order_save_commit_after’. After you created your module you can use your php code which works with database table directly in your observer methods. This code will run every time customer places order. It’s a simple way.
    In sum you should create module exactly like in my example but with your names/namespaces. Instead of ‘sales_order_save_commit_after’ you should use ‘sales_order_place_after’. And in your observer class (Namespace_Custmail_Model_Observer in example) you should use your code to work with database.

  • Nirav

    HI Rogoza,
    Thank you very much. Works like a charm in 1.6.2.0.

  • Pankaj

    awesome article for email template..:)

    can you please let us know how can we use system defined variable in own email template…? ex i want user {{var $order.getCustomerName()}} how should we post this variable in my own template

    • http://www.facebook.com/yaroslav.andreevich.7 Yaroslav Rogoza

      Hi Pankaj.

      You can init order data in the $emailTemplateVariables next way:
      $emailTemplateVariables['order'] = $order->getData();
      and then use the variable in your template:
      {{var order.customer_name}}

  • http://www.facebook.com/yaroslav.andreevich.7 Yaroslav Rogoza

    Hi Gert. Thanks for your reply.

    Try to change:
    singleton
    to
    model

    In the observers section (config.xml)
    In our case no matter which type to use. It may help.

    • Rajesh

      After follow ur solution it resolved this error message. But when i cancelled a order, it is not send cancel mail to the customer. What do i do wrong? Please help
      Thanks

      • http://www.facebook.com/yaroslav.andreevich.7 Yaroslav Rogoza

        Hi Rajesh. How did you cancel the order? If you did it on the orders grid page and mail was not send – try to cancel another order from the order view page.

        • Rajesh

          Thanks for response!

          I am trying to cancel order from admin panel sales order page. when order is cancelled then mail is automatic send to the customer mail id. It’s not happend . please help me.

          Thanks!

          • Rajesh

            Hi Rogoza,
            This issue has been solved. But i have another issue. Can u solve??
            The issue is….
            how would be managed if only part of the order is being dispatched and the remaining cancelled.
            Please guide me if possible.
            Thanks!

          • http://www.atwix.com/ Alexander Turiak

            Hello Rajesh,

            this topic goes beyond the blog post and we do not provide free support service here in comments. Please submit a request through our “Get a quote” page if you want to purchase our services.

  • kaforad

    Thanks for the post. Was so helpful

  • kaforad

    thanks for the info. this line if ($order->getState == Mage_Sales_Model_Order::STATE_CANCELED) has to be

    if ($order->getState() == Mage_Sales_Model_Order::STATE_CANCELED).

    Lot of thanks to Yaroslav Rogoza

    • http://www.facebook.com/yaroslav.andreevich.7 Yaroslav Rogoza

      Hi kaforad. Thank you for your hint. You are completely right. I will fix it.

  • Charl

    Hello
    Thanks for the post.
    Is any one using 1.7? I have been struggling with this for 2 days now and it is still sending the original cancelled email template.
    Thanks

  • http://www.facebook.com/yaroslav.andreevich.7 Yaroslav Rogoza

    Hi João Gabriel
    Thanks for reply, good question.
    First of all, you need to know the event to observe (execute some action). There’s no global event “Order Status Is Changed” in Magento. Globally you can use event sales_order_place_after. When an order was placed – check the order’s status. If the status isn’t normal – you are able to send emails, write emails or do whatever you want :) To send email to several customers just pass an array with emails as the first argument for method Mage::getModel(‘core/email_template’)->send()

    (in the article, source of the file /app/code/community/Namespace/Custmail/Model/Observer.php, line 29, first argument)
    Good luck.