How best to use Swiftmailer for this project?
Moderators: Chris Corbyn, General Moderators
How best to use Swiftmailer for this project?
Hi everyone
I'm going to try using Swiftmailer for the 1st time as it seems absolutely superb!
Here are the requirements...
2,958 recipients.
Personalised message bodies stored in SQL along with the email addresses.
Both HTML and plain text message body.
A 420kb PDF attachment.
With so many recipients it would make sense to pause for a few minutes after every 100.
There's some docs on how to do this on the Swiftmailer site - but does it work with each mail having an individual message body?
Now I have 2 options for sending this...
1) Running this script on our ISP's web host server - I've cleared it with them and we routinely send our email newsletter out to about 8000 people using PHPMailer.
And either connect to their SMTP server or use their sendmail.
2) Or I run the script on our Windows 2000 PHP 5 Apache server, and connect to our local Exchange small business server to send the mails out.
Are the above requirements possible with Swiftmailer?
Which is the best option - 1 or 2?
With the PDF attachment being 423KB, and with 2958 recipients...
(423 x 2958) / 1024
Gives a total email payload of at least 1,221.9MB - so I'm thinking sending through our exchange server would be the way forward.
When running Swiftmailer, is it possible to get log files or status somehow of how many have been sent? And which addresses have errors etc.
Or am I being stupid in thinking we can do this with Swiftmailer?
Thanks
Ben
I'm going to try using Swiftmailer for the 1st time as it seems absolutely superb!
Here are the requirements...
2,958 recipients.
Personalised message bodies stored in SQL along with the email addresses.
Both HTML and plain text message body.
A 420kb PDF attachment.
With so many recipients it would make sense to pause for a few minutes after every 100.
There's some docs on how to do this on the Swiftmailer site - but does it work with each mail having an individual message body?
Now I have 2 options for sending this...
1) Running this script on our ISP's web host server - I've cleared it with them and we routinely send our email newsletter out to about 8000 people using PHPMailer.
And either connect to their SMTP server or use their sendmail.
2) Or I run the script on our Windows 2000 PHP 5 Apache server, and connect to our local Exchange small business server to send the mails out.
Are the above requirements possible with Swiftmailer?
Which is the best option - 1 or 2?
With the PDF attachment being 423KB, and with 2958 recipients...
(423 x 2958) / 1024
Gives a total email payload of at least 1,221.9MB - so I'm thinking sending through our exchange server would be the way forward.
When running Swiftmailer, is it possible to get log files or status somehow of how many have been sent? And which addresses have errors etc.
Or am I being stupid in thinking we can do this with Swiftmailer?
Thanks
Ben
- Chris Corbyn
- Breakbeat Nuttzer
- Posts: 13098
- Joined: Wed Mar 24, 2004 7:57 am
- Location: Melbourne, Australia
Number of recipients is not an issue. If the message bodies are very different you'll be best of just using a loop to send to each recipient with the relevant body, but if it's just something as simple as a name or date changed in the text you might want to search these forums for "swift template plugin" with the "all terms" button checked.
Swift does log everything yes. By default it keeps the log truncated to 100 entries (100 SMTP commands basically) but you can adjust this with setMaxLogSize() and I strongly suggest you do this if you're sending attachments. The reaoson I say that is because attachments are base64 encoded and therefore use approximate 130% of there file size. Then Swift stores a copy for sending, and if you log everything it will also be in the log. By the time you get to 100 log entries you're using a lot of (possibly over the 8MB?) memory. I set the log size to 5, since if something goes wrong you'll see it within the last few commands anyway.
If it's just failed addresses you're looking for you want to check if there are any elements in the array getFailedRecipients() returns. An empty array means all address were accepted for delivery at the SMTP server but does NOT guarantee they will reach their final destination since they need to pass through other MX servers on the way.
With all those attachments I certainly would not send any more than 100 at a time and I'd be tempted to use SMTP over Sendmail because although it's slower it will be less resource intensive. If it were me personally doing this I'd do batches of 50 with a 20 second pause at each 50 messages. Don't forget that if you're sending attachments there will be a certain amount and overhead from TCP traffic.
As for using exchage or your ISP just try both and see what's faster. If your ISP is a busy commercial host it might be fairly slow since they often have busy servers. Exchange uses SMTP anyway so either will work.
For a more verbose checking of failed/successful addresses search these forums for "swift verbose plugin" with the all terms button checked. I knocked one together for somebody a while back.
Good luck
Swift does log everything yes. By default it keeps the log truncated to 100 entries (100 SMTP commands basically) but you can adjust this with setMaxLogSize() and I strongly suggest you do this if you're sending attachments. The reaoson I say that is because attachments are base64 encoded and therefore use approximate 130% of there file size. Then Swift stores a copy for sending, and if you log everything it will also be in the log. By the time you get to 100 log entries you're using a lot of (possibly over the 8MB?) memory. I set the log size to 5, since if something goes wrong you'll see it within the last few commands anyway.
If it's just failed addresses you're looking for you want to check if there are any elements in the array getFailedRecipients() returns. An empty array means all address were accepted for delivery at the SMTP server but does NOT guarantee they will reach their final destination since they need to pass through other MX servers on the way.
With all those attachments I certainly would not send any more than 100 at a time and I'd be tempted to use SMTP over Sendmail because although it's slower it will be less resource intensive. If it were me personally doing this I'd do batches of 50 with a 20 second pause at each 50 messages. Don't forget that if you're sending attachments there will be a certain amount and overhead from TCP traffic.
As for using exchage or your ISP just try both and see what's faster. If your ISP is a busy commercial host it might be fairly slow since they often have busy servers. Exchange uses SMTP anyway so either will work.
For a more verbose checking of failed/successful addresses search these forums for "swift verbose plugin" with the all terms button checked. I knocked one together for somebody a while back.
Good luck
Good news then, I'd like to try sending using SMTP through our own Exchange server to ease load on our ISP's server, but have been having unrelated problems with it over the past few days.
Especially when thinking about 2GB of total mail traffic that this will send out.
Unfortunately the message bodies are pretty different - a whole section of contact / address details gets changed for each recipient.
So where exactly would I run the loop in my script?
Do I have to loop through the whole thing, the connecting to the server part as well?
Obviously I need to change both the plain text and html body parts within each iteration of the loop.
And I just can't figure out where to place the start / end of the loop.
This is my first project with swiftmailer (have always used PHPMailer in the past) and unfortunately it's pretty complex.
I should have some code to post up tomorrow.
Thanks
Ben
Especially when thinking about 2GB of total mail traffic that this will send out.
Ah right, I did wonder why my email with a 420KB PDF arrived to a test account as 530KB or so.d11wtq wrote:attachments are base64 encoded and therefore use approximate 130% of there file size
Unfortunately the message bodies are pretty different - a whole section of contact / address details gets changed for each recipient.
So where exactly would I run the loop in my script?
Do I have to loop through the whole thing, the connecting to the server part as well?
Obviously I need to change both the plain text and html body parts within each iteration of the loop.
And I just can't figure out where to place the start / end of the loop.
This is my first project with swiftmailer (have always used PHPMailer in the past) and unfortunately it's pretty complex.
I should have some code to post up tomorrow.
Thanks
Ben
- Chris Corbyn
- Breakbeat Nuttzer
- Posts: 13098
- Joined: Wed Mar 24, 2004 7:57 am
- Location: Melbourne, Australia
Ok cool.
I've successfully got the mail sending through our exchange server. That's a big improvement and I'll be looking to change our regular email newsletter system over to swiftmailer!
I also think I'm going to ditch the large attachment and send the message with a link for the users to download the attachment off our website instead.
Just to get this email shot out quickly to our customers.
A couple of questions about logging...
Where is the swift log kept?
And to access the getFailedRecipients() array do I just do this...
Then that lets me know which ones were rejected by the SMTP server.
Finally here's my script structure so far...
http://www.dealer-world.net/mailtest.phps
I want to set the script so it runs in the background until it's finished so I don't get the max execution time PHP error.
But then how do I get the getFailedRecipients() if the browser window's closed or already timed out?
The code is...
Where do I need to put that? At the moment in my script I have it within the loop, but does it need to go before the loop starts?
Up near the anti-flood statement?
Or does it go after the end of the loop before the...
... instruction
Thanks
Ben
I've successfully got the mail sending through our exchange server. That's a big improvement and I'll be looking to change our regular email newsletter system over to swiftmailer!
I also think I'm going to ditch the large attachment and send the message with a link for the users to download the attachment off our website instead.
Just to get this email shot out quickly to our customers.
A couple of questions about logging...
Where is the swift log kept?
And to access the getFailedRecipients() array do I just do this...
Code: Select all
$failed_array = getFailedRecipients();Finally here's my script structure so far...
http://www.dealer-world.net/mailtest.phps
I want to set the script so it runs in the background until it's finished so I don't get the max execution time PHP error.
But then how do I get the getFailedRecipients() if the browser window's closed or already timed out?
The code is...
Code: Select all
// RUN IN BACKGROUND UNTIL FINISHED
set_time_limit(0);
ignore_user_abort();
echo "Close the browser window now\r\n";
flush();
ob_flush();Up near the anti-flood statement?
Or does it go after the end of the loop before the...
Code: Select all
$swift->close();Thanks
Ben
- Chris Corbyn
- Breakbeat Nuttzer
- Posts: 13098
- Joined: Wed Mar 24, 2004 7:57 am
- Location: Melbourne, Australia
That sounds like a good idea. If you wanted to track used bandwidth, this (PHP5) plugin works:batfastad wrote:Ok cool.
I've successfully got the mail sending through our exchange server. That's a big improvement and I'll be looking to change our regular email newsletter system over to swiftmailer!
I also think I'm going to ditch the large attachment and send the message with a link for the users to download the attachment off our website instead.
Just to get this email shot out quickly to our customers.
Code: Select all
<?php
class Swift_Plugin_BandwidthMeasure implements Swift_IPlugin
{
public $pluginName = "BW_Measure";
protected $swift = null;
protected $in = 0;
protected $out = 0;
public function loadBaseObject($swift)
{
$this->swift = $swift;
}
public function onCommand()
{
$this->out += strlen($this->swift->currentCommand);
}
public function onResponse()
{
$this->in += strlen($this->swift->lastResponse);
}
public function getTotalBytes()
{
return $this->in + $this->out;
}
public function getBytesIn()
{
return $this->in;
}
public function getBytesOut()
{
return $this->out;
}
}
?>Code: Select all
<?php
$swift = new Swift( .... );
$swift->loadPlugin(new Swift_Plugin_BandwidthMeasure());
$swift->send( .... );
echo $swift->getPlugin("BW_Measure")->getTotalBytes();
?>$swift->transactions;A couple of questions about logging...
Where is the swift log kept?
It's:And to access the getFailedRecipients() array do I just do this...
Then that lets me know which ones were rejected by the SMTP server.Code: Select all
$failed_array = getFailedRecipients();
$failed = $swift->getFailedRecipients();
And yes, it shows the ones which the SMTP server rejected.
Log it into a database. If you close the window then it's gone (until the process ends).Finally here's my script structure so far...
http://www.dealer-world.net/mailtest.phps
I want to set the script so it runs in the background until it's finished so I don't get the max execution time PHP error.
But then how do I get the getFailedRecipients() if the browser window's closed or already timed out?
Put it as early as you can in the script. Once PHP has read those instructions it knows not to kill the script until it's finished, even if the window gets closed.The code is...Where do I need to put that? At the moment in my script I have it within the loop, but does it need to go before the loop starts?Code: Select all
// RUN IN BACKGROUND UNTIL FINISHED set_time_limit(0); ignore_user_abort(); echo "Close the browser window now\r\n"; flush(); ob_flush();
Up near the anti-flood statement?
Or does it go after the end of the loop before the...... instructionCode: Select all
$swift->close();
Thanks
Ben
Hi
Still working on this, getting the script set up exactly how I need.
Just tried the bandwidth plugin and I'm getting the following error...
I saved that PHP code as BandwithMeasure.php and placed it in the /plugins directory where the AntiFlood.php file resides.
Is that because I'm using the PHP5 version of the script on my web server and the plugin code is PHP4?
Also, I'm logging to a field in my recipients database using the following code...
But only the first 16 out of my 24 test recipients are having the database updated
Does the $swift->$transactions log get cleared after every iteration of my loop?
Or does each loop just get appended to this log variable?
If so then that might be the problem - although the transactions field in my MySQL db is set to type TEXT so space shouldn't be an issue.
Thanks
Ben
Still working on this, getting the script set up exactly how I need.
Just tried the bandwidth plugin and I'm getting the following error...
Code: Select all
Fatal error: Declaration of Swift_Plugin_BandwidthMeasure::loadBaseObject() must be compatible with that of Swift_IPlugin::loadBaseObject() in C:\htdocs\fmintranet\emailshot\Swift\Swift\Plugin\BandwidthMeasure.php on line 3Is that because I'm using the PHP5 version of the script on my web server and the plugin code is PHP4?
Also, I'm logging to a field in my recipients database using the following code...
Code: Select all
$transactions = serialize($swift->transactions);
// LOG TO DB
$sql_query = "UPDATE emails_test SET result='OK', transactions='$transactions' WHERE company_id='$company_id' AND email='$email'";
$sql_result = mysql_query($sql_query);Does the $swift->$transactions log get cleared after every iteration of my loop?
Or does each loop just get appended to this log variable?
If so then that might be the problem - although the transactions field in my MySQL db is set to type TEXT so space shouldn't be an issue.
Thanks
Ben
- Chris Corbyn
- Breakbeat Nuttzer
- Posts: 13098
- Joined: Wed Mar 24, 2004 7:57 am
- Location: Melbourne, Australia
That error is fixed like so:
I should really drop that reference in PHP5... that's my lazy self shining through 
$swift->transaction is truncated to save memory. You can specify a maximum size using $swift->setMaxLogSize(...); and use a value of zero for no limit. Be very cautious removing the limit altogether though! There's a lot of data stored there since entire messages will be part of the log
Version 3 will abstract the logging behaviour so you can use a database of a file on the fly without wasting so much memory. In fact, version 3 will offer several places to save memory by using temporary files if allowed to.
Code: Select all
//Change this
public function loadBaseObject($swift)
{
//to this
public function loadBaseObject(&$swift)
{$swift->transaction is truncated to save memory. You can specify a maximum size using $swift->setMaxLogSize(...); and use a value of zero for no limit. Be very cautious removing the limit altogether though! There's a lot of data stored there since entire messages will be part of the log
Version 3 will abstract the logging behaviour so you can use a database of a file on the fly without wasting so much memory. In fact, version 3 will offer several places to save memory by using temporary files if allowed to.
Ok, just sent my email shot out.
Seems so much faster and more efficient than PHPMailer.
Also sending through our own SMTP server (Exchange SBS 2003) is rapid! Previously we've always used our ISPs server but I think this has made our email shotting loads more consistent and accurate.
Congratulations on a fantastic PHP class - I'm very glad Swiftmailer exists!
Thanks for all your help too!
Seems so much faster and more efficient than PHPMailer.
Also sending through our own SMTP server (Exchange SBS 2003) is rapid! Previously we've always used our ISPs server but I think this has made our email shotting loads more consistent and accurate.
Congratulations on a fantastic PHP class - I'm very glad Swiftmailer exists!
Thanks for all your help too!
- Chris Corbyn
- Breakbeat Nuttzer
- Posts: 13098
- Joined: Wed Mar 24, 2004 7:57 am
- Location: Melbourne, Australia
Wait for version 3 if you want performance boosts. It has some fairly intelligent caching features and more ways to lower memory usagebatfastad wrote:Ok, just sent my email shot out.
Seems so much faster and more efficient than PHPMailer.
Also sending through our own SMTP server (Exchange SBS 2003) is rapid! Previously we've always used our ISPs server but I think this has made our email shotting loads more consistent and accurate.
Congratulations on a fantastic PHP class - I'm very glad Swiftmailer exists!
Thanks for all your help too!