Swift Mailer for sending mass email?

Swift Mailer is a fantastic library for sending email with php. Discuss this library or ask any questions about it here.

Moderators: Chris Corbyn, General Moderators

Post Reply
User avatar
bretticus
Forum Newbie
Posts: 4
Joined: Wed May 27, 2009 6:33 pm

Swift Mailer for sending mass email?

Post by bretticus »

I was previously sending approx. 1000 emails via mail() function. The PHP manual doesn't recommend using mail in a loop for mass emails so I started looking at other options. I've heard good things about Swift Mailer and decided to try it.

My script was set for five minutes, however it timed out before I got done. I know I can set the script to never time out but this seems no faster (perhaps slower) than using the mail function. So I have a few questions:
  • Does $mailer->send($message) require a status for each time it is called (as opposed to an async call?)
  • I'm using sendmail configured as a smarthost. Is there some way I can force the messages to be locally queued (again, an async call that just spits out the message and moves on?)
  • Should I not be using Swift Mailer as a mass mailer?
Here is my source code:

Code: Select all

 
<?php
require_once 'lib/swift_required.php';
 
//Create the Transport
$transport = Swift_SendmailTransport::newInstance();
 
//Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);
 
$message = new Swift_Message($title);
$message->setFrom(array(
    FROM_EMAIL => FROM_EMAIL_NAME
));
 
$message->setReturnPath(FROM_BOUNCE);
 
// all this is inside loop for each email user
 
$message->setBody($body, 'text/html');
$message->setTo(array(
    $cols[FIELD_EMAIL] => $recipient_name
));     
 
$mailer->send($message);
 
// end loop
 
?>
Many thanks for reading my post.

UPDATE: I just re-read the documentation. I was using the mail() function after all :) Unfortunately, I can't test this until another email notification mass email is sent out.

My new code has:

Code: Select all

<?php
//Create the Transport
$transport = Swift_SendmailTransport::newInstance('/usr/sbin/sendmail -bs');
?>
Last edited by Benjamin on Fri May 29, 2009 11:04 am, edited 1 time in total.
Reason: Changed code type from text to php.
student101
Forum Newbie
Posts: 20
Joined: Sun Sep 21, 2008 4:04 pm

Re: Swift Mailer for sending mass email?

Post by student101 »

Did you fix it?
User avatar
bretticus
Forum Newbie
Posts: 4
Joined: Wed May 27, 2009 6:33 pm

Re: Swift Mailer for sending mass email?

Post by bretticus »

student101 wrote:Did you fix it?
Fix what exactly? The last code I showed was to skip the mailer function:

Code: Select all

$transport = Swift_SendmailTransport::newInstance('/usr/sbin/sendmail -bs');
...and yes, it is in place. I couldn't just spam 1000 users to see how it goes though. :mrgreen:

However, I noticed my client sent another press release notification this morning. From my apache logs, it appears that it took less than 5 minutes. If that is accurate, this is better performance than I was getting with the mail() function but, perhaps, only slightly, so it may be how my mail server is configured. I don't seem to see sendmail "putting the brakes" on these though (last time *I think* I saw throttling on the web server or the mail server), but I'm not sure and don't have time at the moment to really dig in. I did add my web server to my access list for relay on my mail server and that may have gotten me around the throttling in sendmail (if I did have that problem. I should have taken better notes.) I think I'll write some stats into the client code so it tells me next time, then I won't have to guess. If this script with a sendmail transport simply spits out emails for my mail server to queue, that's awesome. Otherwise, I might have to send directly to my mail server (my web server is configured as a sendmail smarthost.) using the no-flood plugin (if it can send asynchronously.)

I'd still appreciate some feedback to my earlier questions.

Thanks again.
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Re: Swift Mailer for sending mass email?

Post by s.dot »

If you're using $mailer->send() inside of the loop then I reckon that is bad. I use swift mailer to mass send messages and i can easily send 1000 within a minute.

Use the batchSend() method. Use a string with variables in it if you need to personalize the messages and use the decorator plugin to replace the variables. Don't generate the message or subject inside of the loop.
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
User avatar
bretticus
Forum Newbie
Posts: 4
Joined: Wed May 27, 2009 6:33 pm

Re: Swift Mailer for sending mass email?

Post by bretticus »

scottayy wrote:If you're using $mailer->send() inside of the loop then I reckon that is bad. I use swift mailer to mass send messages and i can easily send 1000 within a minute.

Use the batchSend() method. Use a string with variables in it if you need to personalize the messages and use the decorator plugin to replace the variables. Don't generate the message or subject inside of the loop.
Thanks for your reply!

I read batchSend wrong. For some reason I thought this was the equivalent of sending one email to multiple recipients (the To: field having all those emails included.) Also, thanks for the tip with the decorator plugin. There's not a whole lot of documentation (for version 4.0x) and I should have read it more thoroughly. But when I saw, "decorator plugin" it just didn't set off any notions of what it actually accomplishes in my head. :) That's great! That is exactly what I need as the body content needs to be customized per user. I know that my mail server that I relay to throttles after 100 messages (CONNECTION_RATE_THROTTLE.) I assume I still need the anitflood plugin even with batchSend()?

Thanks again.

UPDATE
Both batchSend() and send() methods will work with this plugin.
I guess that's my green light. Thanks!
User avatar
bretticus
Forum Newbie
Posts: 4
Joined: Wed May 27, 2009 6:33 pm

Re: Swift Mailer for sending mass email?

Post by bretticus »

So I just sent 5 emails with the following code:

Code: Select all

//Create the Transport
//$transport = Swift_SendmailTransport::newInstance('/usr/sbin/sendmail -bs');
$transport = Swift_SmtpTransport::newInstance('smpt.server.tld', 25);
 
//Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);
 
//Use AntiFlood to re-connect after 100 emails
$mailer->registerPlugin(new Swift_Plugins_AntiFloodPlugin(100));
                
// get database info.                 
$sql = "SELECT p.`firstName`, p.`lastName`, e.`email`, e.`emailCode` FROM `Emails` e LEFT JOIN `Persons` p ON e.`PersonID` = p.`PersonID` ORDER BY e.`email` ASC";
//$sql = "SELECT `email`, `emailCode` FROM `Emails`";// WHERE `email` LIKE 'brett%'";
//$rows = $data->get_rows($sql);
 
$rows = array(
    array('Brett', 'Obfuscated', 'obfuscated@gmail.com', 'gmail'),
    array('Brett', 'Obfuscated', 'obfuscated@obfuscated.com', 'obfuscated'),
    array('Brett', 'Obfuscated', 'obfuscated@yahoo.com', 'yahoo'),
    array('Brett', 'Obfuscatedt', 'obfuscated@hotmail.com', 'msn'),
    array('Brett', 'Obfuscated', 'obfuscated@obfuscated.org', 'bretticus'),
);      
 
//Build replacement array for decorator plugin and address batch send to all users.
$replacements = array();
foreach ($rows as $cols) {
    // continue on invalid email or empty user guid.
    if ( !$form->isEmail($cols[FIELD_EMAIL]) || empty($cols[FIELD_CODE]) )
        continue;                       
    
    $replacements[$cols[FIELD_EMAIL]] = array(
        '[EMAIL_CODE]'=>$cols[FIELD_CODE]               
    );
}
 
$decorator = new Swift_Plugins_DecoratorPlugin($replacements);
$mailer->registerPlugin($decorator);
 
//create message
$message = Swift_Message::newInstance()
  ->setSubject($_POST['title'])
  ->setFrom(array(FROM_EMAIL => FROM_EMAIL_NAME))
  ->setReturnPath(FROM_BOUNCE)
  ->setBody($body, 'text/html');
  
foreach ($rows as $cols) {
    // continue on invalid email or empty user guid.
    if ( !$form->isEmail($cols[FIELD_EMAIL]) || empty($cols[FIELD_CODE]) )
        continue;
    
    // use full name for recipient if given.
    $recipient_name = ( !empty($cols[FIELD_FIRST]) && !empty($cols[FIELD_LAST]) ) ? 
        $cols[FIELD_FIRST] . ' ' . $cols[FIELD_LAST] : $cols[FIELD_EMAIL];
        
    $message->addTo($cols[FIELD_EMAIL], $recipient_name);
}
                
$numSent = $mailer->batchSend($message);
I have some code to count the time elapsed and it took 8 seconds to process 5 emails. Am I doing something wrong here?

Some of the anti-spam sendmail settings at smtp.server.tld are:

Code: Select all

define('confMAX_MESSAGE_SIZE', 36700160)dnl
FEATURE(`access_db', `hash -T<TMPF> /etc/mail/access')dnl
FEATURE(`greet_pause',1000)dnl
dnl # Options to help cut down on dictionary attacks
define(`confMAX_RCPTS_PER_MESSAGE',`10')dnl
define(`confBAD_RCPT_THROTTLE',`1')dnl
define(`confCONNECTION_RATE_THROTTLE', `100')dnl
define(`confMAX_DAEMON_CHILDREN', `400')dnl
define(`confTO_ICONNECT', `15s')dnl
define(`confTO_CONNECT', `3m')dnl
define(`confTO_HELO', `2m')dnl
define(`confTO_MAIL', `1m')dnl
define(`confTO_RCPT', `1m')dnl
define(`confTO_DATAINIT', `1m')dnl
define(`confTO_DATABLOCK', `1m')dnl
define(`confTO_DATAFINAL', `1m')dnl
define(`confTO_RSET', `1m')dnl
define(`confTO_QUIT', `1m')dnl
define(`confTO_MISC', `1m')dnl
define(`confTO_COMMAND', `1m')dnl
define(`confTO_STARTTLS', `2m')dnl
define(`confTO_QUEUERETURN', `1d')dnl
define(`confQUEUE_LA', `40')dnl
define(`confREFUSE_LA', `50')dnl
define(`confTO_CONNECT', `15s')dnl
I have my mail server ip set at 0 for greetpause in my access file (fyi.)
mpetrovich
Forum Commoner
Posts: 55
Joined: Fri Oct 19, 2007 2:02 am
Location: Vancouver, WA, USA

Re: Swift Mailer for sending mass email?

Post by mpetrovich »

scottayy said:
if you're using $mailer->send() inside of the loop then I reckon that is bad.
I do not believe this to be true. Batch send does exactly this. It takes your list and loops through it and sends each message using send(). It basically automates the looping code.

There are some advantages to putting send() in your own loop. I should note, though, that you want to open a single connection.
1) You have complete control over swapping out any content in your template/message for each message sent. You can change any details in the body, subject or headers, attach dynamic PDFs or images, etc.
2) If you are grabbing a large list from a database and keep all the rows in a memory, you may have memory problems.

We send out up to 50,000 messages this way, where each message is customized. We could not do that with Batch send.

Now, when it comes to speed, there are lots of variables that could affect your performance, such as the mail server used.
Post Reply