array() problem sending mass email with swiftmailing

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

kigoobe
Forum Commoner
Posts: 38
Joined: Mon Jul 10, 2006 3:26 am

Post by kigoobe »

d11wtq wrote:Sounds as though you havn't included the Swift_SMTP_Connection.php file.
That's what I thought at the beginning, but no, I have double checked it, and then, I have uploaded the full package of Swift-1.3.1 without deleteing anything. Besides, Sendmail and SMTP are in the same folder, so if it catches one, why not the other ... weird ...

Also, could you guess why all the mails are going as 'first email' instead of telling first, second and third, as the script has asked. I think if we could solve this issue, everything would have been perfect.

Any idea?
Thanks.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

kigoobe wrote:
d11wtq wrote:Sounds as though you havn't included the Swift_SMTP_Connection.php file.
That's what I thought at the beginning, but no, I have double checked it, and then, I have uploaded the full package of Swift-1.3.1 without deleteing anything.
Can you post the entire script that's giving you that error please? :)
Besides, Sendmail and SMTP are in the same folder, so if it catches one, why not the other ... weird ...
You still need to manually include the file.... Swift *doesn't* do this for you.
Also, could you guess why all the mails are going as 'first email' instead of telling first, second and third, as the script has asked. I think if we could solve this issue, everything would have been perfect.
Ooops.... I commented out $this->count++ before posting here :P (Thanks ~Weirdan)

Code: Select all

<?php

class Swift_Template_Plugin implements Swift_IPlugin
{
        public $pluginName = 'Template';
        private $templateVars = array();
        private $swiftInstance;
        private $template = '';
        private $count = 0;

        //2-dimensional
        // First level MUST be numerically indexed starting at zero
        // Second level contains the replacements
        public function __construct($template_vars=array())
        {
                $this->templateVars = $template_vars;
        }

        public function loadBaseObject(&$object)
        {
                $this->swiftInstance =& $object;
        }

        //Split the headers from the mail body
        private function getTemplate()
        {
                return substr($this->swiftInstance->currentMail[3], strpos($this->swiftInstance->currentMail[3], "\r\n\r\n"));
        }

        private function getHeaders()
        {
                return substr($this->swiftInstance->currentMail[3], 0, strpos($this->swiftInstance->currentMail[3], "\r\n\r\n"));
        }

        public function onBeforeSend()
        {
                if (empty($this->template)) $this->template = $this->getTemplate();

                foreach ($this->templateVars[$this->count] as $key => $replacement)
                {
                        $this->swiftInstance->currentMail[3] = $this->getHeaders().str_replace('{'.$key.'}', $replacement, $this->template);
                        //echo $replacement;
                }
                $this->count++;
        }
}

?>
kigoobe
Forum Commoner
Posts: 38
Joined: Mon Jul 10, 2006 3:26 am

Post by kigoobe »

Hi Chris

I wanted to tell you that I have tested this code, and its working perfectly. A million thanks to you for all your help once again. Besides, things are working pretty well with Swift_Sendmail_Connection.php. In that case do I still need to go for Swift_SMTP_Connection.php?

Thanks.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

kigoobe wrote:Hi Chris

I wanted to tell you that I have tested this code, and its working perfectly. A million thanks to you for all your help once again. Besides, things are working pretty well with Swift_Sendmail_Connection.php. In that case do I still need to go for Swift_SMTP_Connection.php?

Thanks.
Sendmail is faster since it can just spool all the mail in milliseconds to get it out of PHP's hands then sendmail sends out all the emails in batches in the background. I don't see a reason to use SMTP if sendmail works nicely ;)
kigoobe
Forum Commoner
Posts: 38
Joined: Mon Jul 10, 2006 3:26 am

Post by kigoobe »

Cool .... So I leave things as they are now ... thanks again.

Cheers.
matthijs
DevNet Master
Posts: 3360
Joined: Thu Oct 06, 2005 3:57 pm

Post by matthijs »

Does anyone by any chance has a good bookmark for some reading about this sendmail/smtp stuff? I mean not the "hello world this is my first mail" stuff, but some background on how sendmail and smtp works, what positive and negative things are, which to choose when, etc. I'm still having problems getting email send (with swiftmailer), so I would like to delve into it a bit. Thanks!
kigoobe
Forum Commoner
Posts: 38
Joined: Mon Jul 10, 2006 3:26 am

Post by kigoobe »

matthijs, you can read the documents of Swiftmailer, that's pretty well explained. I needed some extra help as I wanted something more than what Swiftmailing was providing. If you have any other problem, I think you can post it here, there are enough helpful guys who can help you out.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

matthijs wrote:Does anyone by any chance has a good bookmark for some reading about this sendmail/smtp stuff? I mean not the "hello world this is my first mail" stuff, but some background on how sendmail and smtp works, what positive and negative things are, which to choose when, etc. I'm still having problems getting email send (with swiftmailer), so I would like to delve into it a bit. Thanks!
I'll try to explain as best I can.

MTA = Mail Transfer Agent
SMTP = Simple Mail Transfer Protocol

SMTP servers are backed by an MTA. In other words, they listen on a certain port (25) and when they get requests they pass them onto the MTA.

SMTP, being a protocol is basically a language for one computer to talk to another.

Computer A wants to send an email.
Computer B is running an SMTP server.

So computer A connects to computer B and says "Hello" almost literally by going "HELO".
Computer B then responds by saying OK and "HELO" again before idnetifying it's capabilities.

Computer A then continues to ask computer B to do things and computer B keeps telling computer A how well it did them.

The general process for sending an email over SMTP would be:

Computer A says HELO
Computer B says OK and HELO
Computer A says it wants to send a mail from some@address
Computer B says yeah fine whatever
Computer A says it want to send this mail to some@address
Computer B says yeah go ahead then, give me the email and I'll send it for you
Computer A then passes the email to computer B
Computer B says thanks I've done that for you, you can either go now or I'll do something else for you.

Now, obviously all of the uses bandwidth and takes time while the two machines talk to each other like this. Using sendmail we can do the same sort of thing but we don't need to bother asking another computer to get invloved immediately. Computer A open sendmail (a program on the machine itself) and tells it what it would tell an SMTP server (no bandwidth uses yet). Sendmail then sticks the message in a queue and does the SMTP stuff when it gets a chance.

From your own point of view, you want to use sendmail if you have it installed (only works on linux) since there is no TCP data being sent whilst the PHP script runs so the whole thing finishes quicker. You also pass the responsibility away from PHP and just let sendmail deal with Computer B by itself.

Actual sequence of commands:
HELO myname.tld <--- This is me saying Hi!
250 w3style.co.uk Hello name.tld [213.205.138.XXX] <--- This is the server saying Hi
MAIL FROM: me@address.com <-- Thi is me asking to send an email
250 OK <-- This is the server saying OK
RCPT TO: chris@w3style.co.uk <-- This is me saying I want the mail to go to this address
250 Accepted <-- Server says OK
DATA <-- Me saying I'm going to give it the email now
354 Enter message, ending with "." on a line by itself <-- Server just being helpful
This is where the email goes <-- My message
.
250 OK id=1G0hKJ-0004JL-LE <-- Server saying yeah sent ok
matthijs
DevNet Master
Posts: 3360
Joined: Thu Oct 06, 2005 3:57 pm

Post by matthijs »

Thanks for the elaborate answer. It's a lot clearer now.

So what is the normal php mail() function using then? Sendmail or smtp?

I just tried following example:

Code: Select all

<?php

require('../../Swift.php');
require('../../Swift/Swift_Sendmail_Connection.php');

$connection = new Swift_Sendmail_Connection;

$mailer = new Swift($connection, $_SERVER['SERVER_NAME']);

//If anything goes wrong you can see what happened in the logs
if (!$mailer->hasFailed())
{
	//Sends a simple email
	$mailer->send(
		'"Joe Bloggs" <joe@bloggs.com>',
		'"Your name" <you@yourdomain.com>',
		'Some Subject',
		"Hello Joe it's only me!"
	);
	//Closes cleanly... works without this but it's not as polite.
	$mailer->close();
}
else echo "The mailer failed to connect. Errors: ".print_r($mailer->errors, 1).". Log: ".print_r($mailer->transactions, 1);

?>
But then WITHOUT the $_SERVER['SERVER_NAME'] and that way I succeeded to send an email.

And another question: which way of sending mail would one like to use for a larger batch of emails? I assumed that if one uses mail(), for each email a new connection to the mailserver is made, which would make the process very ineffective and too slow. A script would time out etc.

Hope these questions aren't too silly. And thanks for all the help.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

mail() uses sendmail on Linux systems and SMTP on windows systems because sendmail isn't available.

mail() does open a new connection for each mail it send yes, Swift keeps the same connection open irhgt up until you call close().

Best for sending a batch email? Same reasoning applies as with normal sending, use sendmail if you can.

Now I'll give a disadvantage of using sendmail over SMTP. If your server isn't too high spec you're going to be launching a new process outside of PHP and whipping commands through it which will use your server's memory and CPU. If you're using SMTP the resources used will be on the SMTP server. I'd still use Sendmail over SMTP if it's there though.
matthijs
DevNet Master
Posts: 3360
Joined: Thu Oct 06, 2005 3:57 pm

Post by matthijs »

Cool. Thanks a lot for all the help. Learned a lot.
lorenww
Forum Newbie
Posts: 7
Joined: Sat Jul 22, 2006 1:41 pm

Post by lorenww »

Weirdan | Please use

Code: Select all

,

Code: Select all

and [syntax="..."] tags where appropriate when posting code. Your post has been edited to reflect how we'd like it posted. Please read:  [url=http://forums.devnetwork.net/viewtopic.php?t=21171]Posting Code in the Forums[/url] to learn how to do it too.[/color]


Perhaps someone here can answer a question.

I ran into the same problem with having to customize the body of each email sent and my host has php4.something.

I need the emails to say "good morning joe" at the top and then provide a custom unsubscribe link for joe@hisdomin.com at the bottom.

(The plugin provided was for php5 and would not work for my purposes and it also would not send multipart.)

I bailed on the "batch" and went with "basic".

here is what I did (snippet) to get it to work.

Code: Select all

while (list ($keylist, $vallist) = each ($dest)) {// at this point $dest has email@email.com|username . . . a for loop will work faster also
$nameaddress = explode("|", $vallist); //separate email from name
if (!$mailer->hasFailed())
{
	//Add as many parts as you need here
	$mailer->addPart("Good morning $nameaddress[1] $headlinestext $unsubscribetext");// text headlines
	$mailer->addPart("Good morning $nameaddress[1] $headlineshtml $unsubscribehtml", 'text/html');
	
	//Leaving the body out of send() makes the mailer send a multipart message
	$mailer->send(

		"\"$nameaddress[1]\" <$nameaddress[0]>",
		"\"My Daily News\" <news@news.org>",
		"$subject"

	);

	}
else {echo "The mailer failed to connect. Errors: ".print_r($mailer->errors, 1).". Log: ".print_r($mailer->transactions, 1);}
	}// end of loop	
	$mailer->close();
I am currently using php mail() which is timing out.

Will this approach to swiftmail be efficient and not cause a time out with 1000+ addresses?

This is for a major organization and testing on all of the addresses is out of the question.


Weirdan | Please use

Code: Select all

,

Code: Select all

and [syntax="..."] tags where appropriate when posting code. Your post has been edited to reflect how we'd like it posted. Please read:  [url=http://forums.devnetwork.net/viewtopic.php?t=21171]Posting Code in the Forums[/url] to learn how to do it too.[/color]
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

If your timeout is 30 seconds you'll get a timeout with 1000 addresses yes. You should be batching them into groups of 100.

Perhaps this could be of use if you want to do it in one shot: http://www.swiftmailer.org/documentation/66#view

As for the template plugin, here's it converted to PHP4.... and yes, it will do multipart emails ;)

Code: Select all

<?php

class Swift_Template_Plugin
{
        var $pluginName = 'Template';
        var $templateVars = array();
        var $swiftInstance;
        var $template = '';
        var $count = 0;

        //2-dimensional
        // First level MUST be numerically indexed starting at zero
        // Second level contains the replacements
        function Swift_Template_Plugin($template_vars=array())
        {
                $this->templateVars = $template_vars;
        }

        function loadBaseObject(&$object)
        {
                $this->swiftInstance =& $object;
        }

        //Split the headers from the mail body
        function getTemplate()
        {
                return substr($this->swiftInstance->currentMail[3], strpos($this->swiftInstance->currentMail[3], "\r\n\r\n"));
        }

        function getHeaders()
        {
                return substr($this->swiftInstance->currentMail[3], 0, strpos($this->swiftInstance->currentMail[3], "\r\n\r\n"));
        }

        function onBeforeSend()
        {
                if (empty($this->template)) $this->template = $this->getTemplate();

                foreach ($this->templateVars[$this->count] as $key => $replacement)
                {
                        $this->swiftInstance->currentMail[3] = $this->getHeaders().str_replace('{'.$key.'}', $replacement, $this->template);
                        //echo $replacement;
                }
                $this->count++;
        }
}

?>
Good luck :)
lorenww
Forum Newbie
Posts: 7
Joined: Sat Jul 22, 2006 1:41 pm

Post by lorenww »

Thank You!

I will dive into that tomorrow as it is getting late here in Florida.

The batches option is perfect also.

I was reading about ignore_user_abort(), previously and also found that a header redirect as soon as the script was initiated kept it running and was what I was doing . . . just sending them back to the admin panel.

also curious, I just saw this today at php.net
set_time_limit(900);

would that keep it alive, I would rather do the batch but was curious about the set_time_limit.

This is a good learning experience
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

lorenww wrote:I was reading about ignore_user_abort(), previously and also found that a header redirect as soon as the script was initiated kept it running and was what I was doing . . . just sending them back to the admin panel.
Thanks, I didn't know about that. I'll test it and see if I can add an option to the plugin to get it automagically background the process by reloading the page with "?___swift_done___" or something :)

EDIT | set_time_limit() does nothing more than increase PHP's timeout from 30 seconds to whatever you specify. So yes, the script *could* run for 900 seconds but will still end normally when the script has executed.
Post Reply