Page 1 of 1

best practice?

Posted: Mon Feb 19, 2007 3:47 pm
by dillion
First I would like to offer my thanks to the author for creating this software! :thumbsup:

In my applications, I use phpmailer for mailing list for a while but after stumbling onto swiftmailer, it is miles better - I guess I am moving over from the dark side of phpmailer! ;)

I do have a few queries I would appreciate if you could clarify (using version 3):

1- Any reason why I should use batchSend instead of normal send (with a do loop), e.g.

Code: Select all

ignore_user_abort();
require_once "../lib/Swift.php";
require_once "../lib/Swift/Connection/SMTP.php";

// SELECT SQL query here

try {
	//Start Swift
	$swift =& new Swift(new Swift_Connection_SMTP("mail.server.com"));
 
	//Create the message
	$message =& new Swift_Message("My subject", "Message body");
	 
	$From = "from@email.com";
        $swift->setReplyTo("contact@email.com");
	
	$i = 1;
	do {
		$email = $row['emailaddress'];
		if($swift->send($message, $email, $From)) {
			$sent = 1;
    	    echo "<span style=\"color:#339900;\">$i: " . $email . "</span><br>";
		} else {
			$sent = 0;
    	    echo "<span style=\"color:#FF0000;\">$i: " . $email . "</span><br>";
		}
		// do some mySQL stuff here, e.g. UPDATE table SET sent=$sent WHERE...
		$i++;
	} while ($row = mysql_fetch_assoc($row_set));
        $swift->close();
 
} catch (Swift_Connection_Exception $e) {
  echo "There was a problem communicating with SMTP: " . $e->getMessage();
} catch (Swift_Message_MimeException $e) {
  echo "There was an unexpected problem building the email:" . $e->getMessage();
}
Is the above code a bad practice or....? The code above is not fully tested and is just based on "theories" and of course would require some anti-flood thing. :)

2- The mailing list system uses a HTML template containing placeholders (e.g. [Forename] [Surname]) - I am aware there's a template plugin for swiftmailer and saw this thread but unsure if it is suitable for version 3?

Many thanks in advance.

Re: best practice?

Posted: Mon Feb 19, 2007 4:11 pm
by Chris Corbyn
dillion wrote:First I would like to offer my thanks to the author for creating this software! :thumbsup:
Thank you kindly :)
I do have a few queries I would appreciate if you could clarify (using version 3):
I'll take my best shot at it.
1- Any reason why I should use batchSend instead of normal send (with a do loop),
Absolutely no reason at all. batchSend() is for convenience above all else, and for familiarity with users of version 2 which did this by default. Unlike version 2, version caches the message inside the message object, not in Swift class so using a loop is *exactly* the same as using batchSend(). When I get around to writing the tutorial on customizing messages this will be a focal point of the new API.

Code: Select all

ignore_user_abort();
require_once "../lib/Swift.php";
require_once "../lib/Swift/Connection/SMTP.php";

// SELECT SQL query here

try {
	//Start Swift
	$swift =& new Swift(new Swift_Connection_SMTP("mail.server.com"));
 
	//Create the message
	$message =& new Swift_Message("My subject", "Message body");
	 
	$From = "from@email.com";
        $swift->setReplyTo("contact@email.com");
	
	$i = 1;
	do {
		$email = $row['emailaddress'];
		if($swift->send($message, $email, $From)) {
			$sent = 1;
    	    echo "<span style="color:#339900;">$i: " . $email . "</span><br>";
		} else {
			$sent = 0;
    	    echo "<span style="color:#FF0000;">$i: " . $email . "</span><br>";
		}
		// do some mySQL stuff here, e.g. UPDATE table SET sent=$sent WHERE...
		$i++;
	} while ($row = mysql_fetch_assoc($row_set));
        $swift->close();
 
} catch (Swift_Connection_Exception $e) {
  echo "There was a problem communicating with SMTP: " . $e->getMessage();
} catch (Swift_Message_MimeException $e) {
  echo "There was an unexpected problem building the email:" . $e->getMessage();
}
Is the above code a bad practice or....? The code above is not fully tested and is just based on "theories" and of course would require some anti-flood thing. :)
The older documentation uses ignore_user_abort() in the same way. It's a hack, but it works. I'll let you make your own decision on using such code, but if it were me, I'd just set up a cron job. FYI, there's an anti-flood plugin in case you didn't already see that.
2- The mailing list system uses a HTML template containing placeholders (e.g. [Forename] [Surname]) - I am aware there's a template plugin for swiftmailer and saw this thread but unsure if it is suitable for version 3?
The plugin API in version 3 has been rewritten. It scared the hell out of people in v2 and was a little over-complex. Old plugins won't work in v3, that's unfortunate I know, but the ones I wrote have been converted, apart from the template one. The reason I didn't convert the template one is because you can handle it yourself better anyway. I will write a plugin for convenience however, but that won't be until I've finished the documentation, which is HUGE priority right now.

If you have replacements to make this works nicely. Key-point here... DO NOT make new message objects, re-use the same one repeatedly so you allow it to use it's cached contents.

Code: Select all

$body = "Hello {name},

Thanks for joining our mailing list blah blah blob blob...";

$subject = "{name} - You are now on our mailing list";

foreach ($users as $email => $name)
{
    $message->setSubject(str_replace("{name}", $name, $subject);
    $message->setBody(str_replace("{name}", $name, $body);
    $swift->send($message, $email, $from);
}
That's not very expensive, most of the heavy-duty work is done within the headers, and here Swift only needs to replace one individual header. The other headers will have been rendered on their first loop and then cached. The body is barely relevant... it's not difficult to re-render.

I will write a plugin. I'm just trying to think of a suitable interface for it. Under-the-hood it will do something similar though.

Hope that helps :)

Re: best practice?

Posted: Mon Feb 19, 2007 6:16 pm
by dillion
Many thanks for your prompt response! :)
d11wtq wrote: Absolutely no reason at all. batchSend() is for convenience above all else, and for familiarity with users of version 2 which did this by default. Unlike version 2, version caches the message inside the message object, not in Swift class so using a loop is *exactly* the same as using batchSend(). When I get around to writing the tutorial on customizing messages this will be a focal point of the new API.

The older documentation uses ignore_user_abort() in the same way. It's a hack, but it works. I'll let you make your own decision on using such code, but if it were me, I'd just set up a cron job. FYI, there's an anti-flood plugin in case you didn't already see that.
I take it that the basic code earlier is OK and won't blow up the server?
The plugin API in version 3 has been rewritten. It scared the hell out of people in v2 and was a little over-complex. Old plugins won't work in v3, that's unfortunate I know, but the ones I wrote have been converted, apart from the template one. The reason I didn't convert the template one is because you can handle it yourself better anyway. I will write a plugin for convenience however, but that won't be until I've finished the documentation, which is HUGE priority right now.

If you have replacements to make this works nicely. Key-point here... DO NOT make new message objects, re-use the same one repeatedly so you allow it to use it's cached contents.

Code: Select all

$body = "Hello {name},

Thanks for joining our mailing list blah blah blob blob...";

$subject = "{name} - You are now on our mailing list";

foreach ($users as $email => $name)
{
    $message->setSubject(str_replace("{name}", $name, $subject);
    $message->setBody(str_replace("{name}", $name, $body);
    $swift->send($message, $email, $from);
}
That's not very expensive, most of the heavy-duty work is done within the headers, and here Swift only needs to replace one individual header. The other headers will have been rendered on their first loop and then cached. The body is barely relevant... it's not difficult to re-render.

I will write a plugin. I'm just trying to think of a suitable interface for it. Under-the-hood it will do something similar though.
So basically, you just declare a message body outside the loop and just do a string replacement within the loop? Could this work with multiple string replacements (e.g. forename, surname, email address, campaign id, subscriber's id, etc. so a fair amount of replacements!)? Also am I restricted to using just one custom parameter in the setBody function (str_replace("{name}")?
Hope that helps :)
It sure did!
On a side note, I was looking through the files of version 2.1.7 and saw a pic of Durham - I was a Hatfielder for four years. :)

Posted: Mon Feb 19, 2007 6:44 pm
by Chris Corbyn
I went to Van Mildert for 3 years ;)

Yes, provided you keep re-using the same string and the same message object this is pretty cheap. I'll make a wrapper/plugin for it in future though :)

str_replace() can take an array of searches/replacements too:

Code: Select all

$text = "bob said {foo} to {bar}";

$search = array("{foo}", "{bar}");
$replace = array("hello", "bryn");

echo str_replace($search, $replace, $text); //bob said hello to bryn
On a side note, I just released the full versions ;) Now I'm off to bed! It's late and I have to be up early :(

Posted: Tue Feb 20, 2007 2:18 am
by dillion
d11wtq wrote:I went to Van Mildert for 3 years ;)
Ah nice one, it's a small world afterall! :D
d11wtq wrote: Yes, provided you keep re-using the same string and the same message object this is pretty cheap. I'll make a wrapper/plugin for it in future though :)

str_replace() can take an array of searches/replacements too:

Code: Select all

$text = "bob said {foo} to {bar}";

$search = array("{foo}", "{bar}");
$replace = array("hello", "bryn");

echo str_replace($search, $replace, $text); //bob said hello to bryn
So in theory I could do the following code:

Code: Select all

$body = "Hello {name},

Thanks for joining our mailing list blah blah blob blob...Your email address is {email}";

$subject = "{name} - You are now on our mailing list";

foreach ($users as $email => $name)
{
    $search = array("{name}", "{email}");
    $replace = array($name, $email);
    $message->setSubject(str_replace("{name}", $name, $subject);
    $message->setBody(str_replace($search, $replace, $body));
    $swift->send($message, $email, $from);
}
Also can I just assume I need to insert a full HTML source code in the $body rather than loading in a HTML file/template?
On a side note, I just released the full versions ;) Now I'm off to bed! It's late and I have to be up early :(
Just noticed it, cheers for the heads-up - I will download it and replace the RC3 version. Ouch, hope you managed to get a decent sleep! :D

Posted: Tue Feb 20, 2007 4:24 am
by Chris Corbyn
You can load files into the body, however, for templating to work in that way I would certainly have to write a plugin.

To (generally) use a file for the body:

Code: Select all

$message->setBody(new Swift_File("your-template.tpl"));
This is mostly intended for attachments, but the same mechanism works for any bulk of the message body due to the underlying MIME layer on which the entire message library is built. Swift_File() streams data from disk, rather than directly copying the whole thing.

Posted: Tue Feb 20, 2007 12:54 pm
by dillion
Many thanks for your answers -- they have definitely clarified my queries. :)