8

I see a strange behaviour in one of our shops: when an order is placed, the confirmation email is sent in CC to all registered customers that have an order in state "processing". It happens independent of the payment method (bank transfer and credit card are available) and the shipping method (only magento flat standard available).

The shop-setup is pretty basic with one website/store/store view. Installed extensions include nothing order- or checkout-related except the extension of the credit card's payment provider.

2
  • Thanks for the code simonthesorcerer. I'm having the same issue. All emails in Magento 1.9.1 are being sent to all customers with open orders (processing or pending). I haven't found an event based solution or any solution for that matter. I did try your solution but it did not work. In app/code/local/, I did not have any of the following folders/files: Namespace/EmailQueueFix/etc/config.xml Namespace/EmailQueueFix/Model/Resource/Email/Queue.php So I created the folders and files and copied the code you wrote. It did not resolve the issue though. Did you create the above folders/files or are m
    – JK9
    Commented Jul 14, 2015 at 22:08
  • HI, the code is an extension, so it's correct that you had to create the folders/files manually. What this code does is: every time the magento-cronjob removes all sent messages from the core_email_queue database table, it also removes all recipients of these messages. So, basically, it did not work for you because this cronjob-task has to run at least once before it takes effect. Commented Jul 15, 2015 at 7:15

3 Answers 3

7

Attention!

What this code does is: every time the magento-cronjob removes all sent messages from the core_email_queue database table, it also removes all recipients of these messages. So, basically, it does not work for you until this cronjob-task has run at least once.

Solution

I found the answer thanks to another question here: the core_email_queue_recipients table was not emptied by the cronjob. The method Mage_Core_Model_Email_Queue::cleanQueue() calls Mage_Core_Model_Resource_Email_Queue::removeSentMessages(), which is pretty simple:

public function removeSentMessages() {
    $this->_getWriteAdapter()->delete($this->getMainTable(), 'processed_at IS NOT NULL');
    return $this;
}

Anyway, this method does not remove the old recipients. Thus, as soon as a new message with message_id n is queued, all old recipients with message_id n will also get the new email. The thing I don't understand is: why has the core team not seen this, and why doesn't this lead to more issues?

I wrote a small module to fix this. It uses a class override for Mage_Core_Model_Resource_Email_Queue, so if anybody can suggest a better (event-based?) solution, I would be glad.

app/code/local/Namespace/EmailQueueFix/etc/config.xml

<?xml version="1.0"?>
<config>
    <modules>
        <Namespace_EmailQueueFix>
            <version>1.0</version>
        </Namespace_EmailQueueFix>
    </modules>
    <global>
        <models>
            <core_resource>
                <rewrite>
                    <email_queue>Namespace_EmailQueueFix_Model_Resource_Email_Queue</email_queue>
                </rewrite>
            </core_resource>
        </models>
    </global>
</config>

app/code/local/Namespace/EmailQueueFix/Model/Resource/Email/Queue.php

<?php

class Namespace_EmailQueueFix_Model_Resource_Email_Queue extends Mage_Core_Model_Resource_Email_Queue {
    /**
     * Remove already sent messages
     * ADDED: also remove all recipients of sent messages!
     *
     * @return Mage_Core_Model_Resource_Email_Queue
     */
    public function removeSentMessages() {
        $writeAdapter = $this->_getWriteAdapter();
        $readAdapter = $this->_getReadAdapter();
        $select = $readAdapter->select()->from(array("ceqr" => $this->getTable('core/email_recipients')), array('*'))->joinLeft(array('ceq' => $this->getMainTable()), 'ceqr.message_id = ceq.message_id', array('*'))->where('ceq.processed_at IS NOT NULL OR ceq.message_id IS NULL');
        $recipients = $readAdapter->fetchAll($select);
        if ( $recipients ) {
            foreach ( $recipients as $recipient ) {
                $writeAdapter->delete($this->getTable('core/email_recipients'), "recipient_id = " . $recipient['recipient_id']);
            }
        }
        $writeAdapter->delete($this->getMainTable(), 'processed_at IS NOT NULL');
        return $this;
    }

}

app/etc/modules/Namespace_EmailQueueFix.xml

<?xml version="1.0"?>
<config>
    <modules>
        <Namespace_EmailQueueFix>
            <codePool>local</codePool>
            <active>true</active>
        </Namespace_EmailQueueFix>
        <depends>
            <Mage_Core/>
        </depends>
    </modules>
</config>
2

I've post a different fix that doesn't require to install a new module, and probably is a little cleaner.

It just uses a foreign key constraint on the core_email_queue_recipients table to delete Recipients records on cascade.

By using this new foreign key, no orphan records will be left on the core_email_queue_recipients table when cleaning the core_email_queue table, so no duplicated messages will be further sent to wrong recipients.

You can find the detailed solution on this post: https://magento.stackexchange.com/a/87299/23057

1
  • IMO this is a cleaner solution and the foreign key should be included by default.
    – micwallace
    Commented Jul 25, 2016 at 6:48
1

This is a problem of indexes in the database. You can repair it with Magento database repair tool.

http://merch.docs.magento.com/ce/user_guide/magento/database-repair-tool.html

The problem cause me a lot of frustration. In my case it was originated from version upgrade. It is a good practice every time that you make a version upgrade to make a clean installation in another directory and in a new empty reference database an then use the tool to compare that the structure and indexes in your database are declared as in the new empty reference database. This structure is what the new version needs! Be aware that the problem is not of bad indexes and can not be solved with re-indexing. More is is a problem of missing indexes as i see it. Always keep backup copies of database before running the tool! It is a pity that even if you reinstall Magento, index and structure verification of database is not given as an option and you have to follow the above procedure. (in my case was upgrading from version 1.8 to 1.9).

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.