Decorator plug-in replaces with wrong information
Posted: Mon Aug 06, 2007 12:01 pm
I'm using Swift 3.2.6 on PHP5 using localhost SMTP server and almost everything is working great!
I followed the ideas in the Using Swiftmailer to send bulk messages with CRON and it has worked like a CHAMP! I was using PHPMailer before and it just doesn't compare. This has really solved our problem of emails getting hung and/or overloading the SMTP server.
On to the problem... I am using the Decorator plug-in to populate the userid and password of the recipient for their login. Some emails are receiving the wrong information!! It only happens about once out of every 100-200 emails, but it happens... and, since it is login information, it is critical obviously.
I've tested this with test email lists of hundreds of recipients and it will occasionally happen, but I have not been able to reproduce it at will -- it happens sometimes and othertimes it won't. I have a cron job running every minute that sends the most recent unsent 100 email messages. This only seems to happen when the cron job is running... when I have manually kicked things off I don't ever remember a recipient getting the incorrect information. The name and email address will be correct -- just the replacement values within the email will be for someone else.
The code for the cron job is below. The tables are almost exactly like the ones outlined in the cron thread with just a few added fields.
The "replacements" field in the mail_user_messages is a serialized array and the information in all of those records is correct. So, the problem is definitely being generated in this cron job somehow.
Thank you very much in advance!! I am pulling my hair out over this one![/url][/i]
I followed the ideas in the Using Swiftmailer to send bulk messages with CRON and it has worked like a CHAMP! I was using PHPMailer before and it just doesn't compare. This has really solved our problem of emails getting hung and/or overloading the SMTP server.
On to the problem... I am using the Decorator plug-in to populate the userid and password of the recipient for their login. Some emails are receiving the wrong information!! It only happens about once out of every 100-200 emails, but it happens... and, since it is login information, it is critical obviously.
I've tested this with test email lists of hundreds of recipients and it will occasionally happen, but I have not been able to reproduce it at will -- it happens sometimes and othertimes it won't. I have a cron job running every minute that sends the most recent unsent 100 email messages. This only seems to happen when the cron job is running... when I have manually kicked things off I don't ever remember a recipient getting the incorrect information. The name and email address will be correct -- just the replacement values within the email will be for someone else.
The code for the cron job is below. The tables are almost exactly like the ones outlined in the cron thread with just a few added fields.
The "replacements" field in the mail_user_messages is a serialized array and the information in all of those records is correct. So, the problem is definitely being generated in this cron job somehow.
Code: Select all
$max_emails = 100;
$user_messages = $db->GetAll("SELECT * FROM mail_user_message WHERE status='U' ORDER BY message_id, id LIMIT $max_emails");
// If nothing needs to be sent, exit
if ( count($user_messages) == 0 ) {
exit;
}
// Get message IDs for user_messages that need to be sent out
foreach ( $user_messages as $user_message ) {
if ( !in_array($user_message['message_id'], $message_ids) ) {
$message_ids[] = $user_message['message_id'];
}
//Collect recipient IDs for use later
$user_message_ids[] = $user_message['id'];
}
$messages = $db->GetAssoc("SELECT message_id, mail_message.*
FROM mail_message
WHERE message_id IN (" . implode(',', $message_ids) . ")
ORDER BY message_id");
// Send emails
if ( count($user_messages) > 0 ) {
// Set status to 'I' (In Progress) for messages
// This is in case the next cron job kicks off before the last one has completed
$db->Execute("UPDATE mail_user_message
SET status='I', updated=" . $db->qstr(date("Y-m-d H:i:s")) ."
WHERE id IN (" . implode(',', $user_message_ids) . ")"
);
// Connect to localhost SMTP
$smtp =& new Swift_Connection_SMTP('localhost');
$swift =& new Swift($smtp);
$batch =& new Swift_BatchMailer($swift);
foreach ( $user_messages as $key => $user_message ) {
unset($id, $message_id, $to_email, $to_name, $replacements);
extract($user_message);
//Build up a list of recipients for each unique message
if ( $key == 0 || $old_message_id <> $message_id ) {
//Send this batch
if ( $key <> 0 ) {
//Load the plugin with these replacements
$swift->attachPlugin(new Swift_Plugin_Decorator($swift_replacements), "decorator");
$batch->send($swift_message, $list, $swift_sender);
}
$list =& new Swift_RecipientList();
$swift_message = null;
$swift_sender = null;
$swift_replacements = array();
$old_message_id = $message_id; //For tracking in the loop
unset($subject, $from_email, $from_name, $replyto, $body);
$message = $messages[$message_id];
extract($message);
}
//No need to repeatedly create $message or $sender in the loop
if ($swift_message === null) {
$swift_message =& new Swift_Message($subject);
// Add reply-to emails
$replyto = unserialize($replyto);
if ( is_array($replyto) && count($replyto) > 0 ) {
$swift_message->setReplyTo($replyto);
} else {
$swift_message->setReplyTo('noreply@mydomain.net');
}
// Undeliverable emails go here
$swift_message->setReturnPath('bounces@mydomain.net');
//Add some "parts"
$text_body = strip_tags(str_replace(array('<br>', '</p>'), array("\n", "\n\n"), $body));
// TESTING
$swift_message->attach(new Swift_Message_Part($text_body));
$swift_message->attach(new Swift_Message_Part($body, 'text/html'));
}
if ($swift_sender === null) $swift_sender =& new Swift_Address($from_email, $from_name);
$list->addTo($to_email, $to_name);
$swift_replacements[$to_email] = unserialize($replacements);
//Collect recipient IDs for use later
$ids[] = $id;
} // foreach $user_message
//Load the plugin with these replacements
$swift->attachPlugin(new Swift_Plugin_Decorator($swift_replacements), "decorator");
$batch->send($swift_message, $list, $swift_sender);
// Update messages so that they will not be sent again later
if ( count($ids) > 0 ) {
// Get failed recipients now that entire batch has gone
$failures = $batch->getFailedRecipients();
//Filter for use in SQL (and add single quotes)
foreach ($failures as $key => $value) {
$failures[$key] = "'" . mysql_real_escape_string($value) . "'";
}
// All messages were successful, so update database
if ( count($failures) == 0 ) {
// Set status to 'S' (Sent) for successful messages
$db->Execute("UPDATE mail_user_message
SET status='S', updated=" . $db->qstr(date("Y-m-d H:i:s")) ."
WHERE id IN (" . implode(',', $ids) . ")"
);
// Some messages had errors -- flag the ones that failed
} else {
// Set status to 'S' (Sent) for successful messages
$db->Execute("UPDATE mail_user_message
SET status='S', updated=" . $db->qstr(date("Y-m-d H:i:s")) ."
WHERE id IN (" . implode(',', $ids) . ")
AND to_email NOT IN (" . implode(',', $failures) . ")"
);
// Set status to 'F' (Failed) for unsuccessful messages
$db->Execute("UPDATE mail_user_message
SET status='F', updated=" . $db->qstr(date("Y-m-d H:i:s")) ."
WHERE id IN (" . implode(',', $ids) . ")
AND to_email IN (" . implode(',', $failures) . ")"
);
}
} // count($ids)
//Disconnect from SMTP, we're done
$swift->disconnect();
// Reset all variables -- it seems like something is sticking around here
unset($swift, $swift_message, $swift_sender, $list);
} // if count($mail) > 0