Sending shipment email when tracking info is added

January 22, 2014  |  3 Comments  |  by Raj (MagePsycho)  |  Latest, Magento

From the topic of this blog post it’s clear that we are going to discuss on ‘How to send shipment email when tracking info is added to the system?’
This may by useful if carrier tracking info is pushed to Magento by some third party system and want to send shipment email.

As usual, instead of rewriting core classes we will be using event-observer pattern.
And events used here will be: sales_order_shipment_save_before & sales_order_shipment_save_after

1. Register the events: sales_order_shipment_save_before & sales_order_shipment_save_after
File: app/code/local/MagePsycho/Shipmentemail/etc/config.xml

...
<global>
    <events>
        <sales_order_shipment_save_before>
            <observers>
                <magepsycho_shipmentemail_sales_order_shipment_save_before>
                    <type>singleton</type>
                    <class>magepsycho_shipmentemail/observer</class>
                    <method>salesOrderShipmentSaveBefore</method>
                </magepsycho_shipmentemail_sales_order_shipment_save_before>
            </observers>
        </sales_order_shipment_save_before>
        <sales_order_shipment_save_after>
            <observers>
                <magepsycho_shipmentemail_sales_order_shipment_save_after>
                    <type>singleton</type>
                    <class>magepsycho_shipmentemail/observer</class>
                    <method>salesOrderShipmentSaveAfter</method>
                </magepsycho_shipmentemail_sales_order_shipment_save_after>
            </observers>
        </sales_order_shipment_save_after>
    </events>
</global>
...

2. Send email using observer model
File: app/code/local/MagePsycho/Shipmentemail/Model/Observer.php

<?php
/**
 * @category   MagePsycho
 * @package    MagePsycho_Shipmentemail
 * @author     magepsycho@gmail.com
 * @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 */
class MagePsycho_Shipmentemail_Model_Observer
{
    protected function _isValidForShipmentEmail($shipment)
    {
        $trackingNumbers = array();
        foreach ($shipment->getAllTracks() as $track) {
            $trackingNumbers[] = $track->getNumber();
        };
        // send shipment email only when carrier tracking info is added
        if (count($trackingNumbers) > 0) {
            return true;
        } else {
            return false;
        }
    }
    
    public function salesOrderShipmentSaveBefore(Varien_Event_Observer $observer)
    {
        if (Mage::registry('salesOrderShipmentSaveBeforeTriggered')) {
            return $this;
        }

        /* @var $shipment Mage_Sales_Model_Order_Shipment */
        $shipment = $observer->getEvent()->getShipment();
        if ($shipment) {
            if ($this->_isValidForShipmentEmail($shipment)) {
                $shipment->setEmailSent(true);
                Mage::register('salesOrderShipmentSaveBeforeTriggered', true);
            }
        }
        return $this;
    }
    
    public function salesOrderShipmentSaveAfter(Varien_Event_Observer $observer)
    {
        if (Mage::registry('salesOrderShipmentSaveAfterTriggered')) {
            return $this;
        }
       
        /* @var $shipment Mage_Sales_Model_Order_Shipment */
        $shipment = $observer->getEvent()->getShipment();
        if ($shipment) {
            if ($this->_isValidForShipmentEmail($shipment)) {
                $shipment->sendEmail();
                Mage::register('salesOrderShipmentSaveAfterTriggered', true);
            }
        }
        return $this;
    }
}

Notes:

  • We have used both events: sales_order_shipment_save_before & sales_order_shipment_save_after. _before is used to set the email_sent flag to true and _after event to send email.
  • If you combine methods: $shipment->setEmailSent(true) and $shipment->sendEmail() in _before event, you will get shipment email but without shipment number.
  • If you combine methods: $shipment->setEmailSent(true) and $shipment->sendEmail() in _after event, it will go in recursive infinite loop sending you the millions of email.

Thanks for reading & sharing.