The basic problem is this: We've enabled the creation of invoices for free (zero subtotal) orders. This works fine, and the invoice is created, except the invoice email isn't sent.

I expected that I just needed to override the method wherever they get created, probably just to add an $invoice->sendEmail(), but I'm having trouble finding where exactly this would be.

  • Which version of Magento are you running? Commented Apr 24, 2015 at 19:25
  • 1
    Sorry, this is EE
    – Mike
    Commented Apr 24, 2015 at 19:29
  • That does change things a bit. i've updated the suggested answer with more details that are relevant to the version of EE you're running. Commented Apr 24, 2015 at 19:37
  • 1
    Yeah, as I mentioned, they are enabled, everything works as expected, except this specific case. I even used the highly advanced method of adding some Mage::log() statements in there and it doesn't appear that Mage_Sales_Model_Order_Invoice::sendEmail() is getting called, so that's why I was hoping to just go look at the point at which the invoice is created.
    – Mike
    Commented Apr 24, 2015 at 19:40
  • 1
    Thanks - yeah that's the what I was thinking about, just doing something with an observer and checking each new Invoice, seeing if all the email settings would normally have sent the email, and if they would and it's a free order, send it then.
    – Mike
    Commented Apr 24, 2015 at 19:55

1 Answer 1


Assuming you have setup the outbound email addresses properly in Menu > System > Configuration : Store Email Addresses :

Menu > System > Configuration : Store Email Addresses Configuration

Browse to the Sales : Sales Emails tab in the same interface as above and expand the Invoice accordion menu: Sales : Sales Emails tab Invoice Email Settings

You'll need to ensure :

  1. That Invoice Emails are Enabled
  2. That you have selected a From address based on the one you configured above. This example uses Sales Representative, but you can select any properly configured email address.
  3. That a template is selected for registered users (if you're testing registered users)
  4. That a template is selected for guest users (if you're testing guest users)

I took these screenshots on CE 1.9.1, but settings should be similar in EE. The version of Magento EE you're using doesn't utilize the new queue system, so as long as you've configured these settings properly, and you implement a custom observer similar to the code in this blog post, your invoice emails should be sent.

The key is to have your custom module attach an observer to the sales_order_invoice_save_after event - after the invoice is saved, you can query the contents of the invoice and fire off an email.


If your goal is to ensure that this functionality is applied to downloadable products in the Zero Subtotal Checkout Invoices like it might be for more regular products, as @xinqiu noted in the comments, you should probably attach your observer to the sales_order_invoice_save_commit_after event instead.

When sales_order_invoice_save_after is fired, the write operation containing the details of the purchased downloadable product link has not yet been saved to the database, even though other order/invoice and other line item information may have been.

Although this is an area in which I have zero direct experience, my understanding is that if there is some failure at the database level and the transaction is rolled back by MySQL, the url that was originally created for the unique downloadable product link would be regenerated by Magento when it retries the save/commit operation

Put more succinctly, one can't know that unique URL have been safely persisted in the database and committed successfully in a db transaction until the sales_order_invoice_save_commit_after event is fired (even if other high-level order details have been committed in MySQL already like totals, order / invoice number, etc...)

Although I haven't had a chance to try it our yet on my own, I can't seem to find a flaw in the logic of that strategy (though this may possibly be one of the areas in which I am much less experienced than I would prefer). I'm guessing you should be able to confirm that with after a little digging around and experimenting - when briefly experimenting on my own I must confess that I feel it might be more prudent to use sales_order_invoice_save_commit_after...

...no matter what kind of products you're dealing with on your Magento Store...Given its (later) sequence in the overall Magento Ordering / Invoicing Workflow, at a minimum you would at least know at this point that all relevant order and line item details had been stored and either generated an exception of some sort and been appropriately rolled back and retried / or its behaving as normally expected.

Assuming you want to include the link to your downloadable product in the template you're using to generate your Invoice email, you should modify the code I include below to attach to sales_order_invoice_save_commit_after which will ensure that all relevant info about the order and any downloadable products are saved in the database and committed in a transaction (if possible).

I can't see why using sales_order_invoice_save_commit_after might introduce any other problems, though please note the caveat that I have never done so myself and the code I provide below I have used several successfully a few times so I might be wrong & "Your Mileage May Vary."


The module code in that example is pretty simple. By default, the send Invoice email function is only triggered for $0.00 Invoice when you click the button in the Admin interface to manually send an email of the Invoice to the Customer (It's automatically sent if the total < 0).

The above code fires the same logic as the button, but is triggered when the event triggers the observer. The solution is 3 basic components :

Module config.xml :


Observer Code :

class Havsund_Autoorder_Model_Observer

/* @var Magento_Sales_Model_Order_Invoice */
var $_invoice;

* Mage::dispatchEvent($this->_eventPrefix.'_save_after', $this->_getEventData());
* protected $_eventPrefix = 'sales_order';
* protected $_eventObject = 'order';
* event: sales_order_save_after
public function automaticallyInvoiceShipCompleteOrder($observer)
   try {
      /* @var $order Magento_Sales_Model_Order_Invoice */
      $this->_invoice = $observer->getEvent()->getInvoice();

   } catch (Mage_Core_Exception $e) {
       Mage::log("HAVSUND AUTOORDER: Fehler #58 " . $e->getMessage());

   return $this;


Module Activation Config :

<?xml version="1.0"?>

NOTE: If you have compilation enabled, you'll have to disable / recompile after you deploy your customization for it to be executed, or you might get an error like:

Warning: get_class() expects parameter 1 to be object, boolean given in /app/code/core/Mage/Core/Model/App.php on line 1340

  • 1
    Thanks, but we do have that all enabled - emails go out for invoices entirely normal in other cases, just not when it's a zero subtotal checkout.
    – Mike
    Commented Apr 24, 2015 at 19:28
  • 1
    Understood. That's the default behavior of the Magento core observer & event system for Invoices. The code sample above should allow you to override that default behavior and since you're not modifying the core files themselves, your changes will last after you perform your next upgrade ;) Commented Apr 24, 2015 at 20:21
  • 1
    Well, I was going to override them, not change them in situ, but yeah, observer is nicer anyway.
    – Mike
    Commented Apr 24, 2015 at 20:56
  • 1
    I actually just ended up using an observer on the sales_order_invoice_save_commit_after event that checks to see if an email has yet been sent for that invoice, and if not, calls sendEmail(). I don't know if this the ideal solution, but it seems to be working for me.
    – Mike
    Commented Jul 6, 2015 at 17:34
  • 1
    Agree with Mike, need to overwrite sales_order_invoice_save_commit_after. Otherwise, the downloadable product will not write to database at the time of sales_order_invoice_save_after. And the invoice email sent at this time, will not have the downloadable link.
    – xinqiu
    Commented Jun 8, 2017 at 9:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.