Page 1 of 2
Bounce Code required
Posted: Mon Mar 19, 2007 9:29 am
by balim
Hi
I send a newsletter to 10k+ recipients.
To handle this, I wrote a function that uses the socket php functions. So I put Line by Line to the other Mailserver:
Code: Select all
fputs($connection, "HELO $mydomain\r\n");
I've a cron script that calls the function in a loop.
Now my Problem:
The transmission is very slow, so I could be >24h to send out all newsletter.
I've look around and found the swift mailer.
This looks pretty nice, so I lovely want to use it for my application.
But is it possible to return the bounce-code (e.g. 540) if a failure occurs?
At the moment, I do it so:
Code: Select all
fputs($connection, "HELO $mydomain\r\n");
$res=fgets($connection,1024);
if(substr($res,0,3) != "250"){
$ret = substr($res,0,3);
fputs($connection, "QUIT\r\n");
fclose ($connection);
return $ret;
}
I important for my statistic modul to get these code. I've to find out if it is a hard or soft bounce, to set the recipients to inactive if so.
I hope you understand what I mean
Greetings and thanks,
Thomas
Posted: Mon Mar 19, 2007 10:51 am
by Chris Corbyn
You'd have to write a plugin. Fairly simple really, but the plugin API differs slightly between PHP4 and 5.
PHP5:
Code: Select all
class ResponseCodeDumper implements Swift_Events_ResponseListener
{
public function responseReceived(Swift_Events_ResponseEvent $e)
{
echo $e->getCode(); //The response code
}
}
PHP4:
Code: Select all
class ResponseCodeDumper extends Swift_Events_Listener
{
function responseReceived(&$e)
{
echo $e->getCode();
}
}
Fiddle with that to wrap it up however you want
Use like so:
Code: Select all
$swift = new Swift( ... );
$swift->attachPlugin(new ResponseCodeDumper());
You might want to read "Writing Plugins" from here:
http://www.swiftmailer.org/wikidocs/
Posted: Mon Mar 19, 2007 11:18 am
by balim
Thanks for the fast answer.
I'm going to read a little bit in the wiki

Posted: Wed Apr 18, 2007 7:45 am
by balim
After my holiday I could continuing on the project.
I had included your response plugin, but if I send a mail to a non existing email address, I get the response codes: 250,250,354,250 (which means, everything is ok). That's not correct!
If the mail address doesn't exists, the mailserver should send a failure code (511) back. I've tested it with big mail provider (e.g. google, gmx) and with non existing domains (
foo@thisdomaindoesntexists.com).
Is there a failue at the response plugin or in the way I use it?
I hope you could help me with my problem.
Code (php4):
Code: Select all
...
include CONF_INCDIR."swiftmailer/Swift.php";
require_once CONF_INCDIR."swiftmailer/Swift/Connection/SMTP.php";
class ResponseCodeDumper extends Swift_Events_Listener
{
function responseReceived(&$e)
{
if (substr($e->getCode(), 0, 1) != 2 && $e->getCode() != 354) {
echo "error: ".$e->getCode()."<br>";
} else {
echo "code: ".$e->getCode()."<br>";
}
}
}
$conn =& new Swift_Connection_SMTP("my_mailserver", 25);
$swift =& new Swift($conn);
$swift->attachPlugin( new ResponseCodeDumper(), "bounce-response");
$query = "SELECT * FROM newsletter_query WHERE mailflag = '' LIMIT 0,100"; // Read the personalized newsletter from Database
$db->query($query);
while ($db->next_record()){
$message =& new Swift_Message($db->f("betreff"));
$newsletter_uid = $db->f("newsletter_uid");
if ("" != $db->f("htmltext")) {
$message->attach(new Swift_Message_Part(stripslashes($db->f("htmltext")), "text/html"));
} else {
}
$message->attach(new Swift_Message_Part(stripslashes($db->f("plaintext"))));
$to =& new Swift_Address("asdf@nonexistingdomain.com", "test");
$from =& new Swift_Address("foo@bar.com", "test");
var_dump($swift->Send($message, $to, $from));
}
...
Posted: Wed Apr 18, 2007 7:51 am
by Chris Corbyn
That's not Swift's fault if the mail server says 250. The mail server you send through cannot check the address other than the domain, and some do not even check that. If the server is authorative for that domain (i.e. it's the master MX) then yes, maybe it would throw a 5XX error but Swift can only tell you what your mail server says.
If you want to debug and see exactly what your mail server is doing then try this:
Code: Select all
$swift = new Swift($domain, null, SWIFT_ENABLE_LOGGING);
//send messages etc etc then at the end:
echo "<pre>" . $swift->log->dump() . "</pre>";
If 250 comes back then your server is doing that, most probably because it's an outgoing relay server with a smarthost (i.e. it's passing the mail to another server to handle the request first).
Posted: Wed Apr 18, 2007 10:05 am
by balim
thanks
Sadly, i could send email to every mail address, if exists or not, and get a successful response (250).
But I've an idea what this could be.
In my own class I made a mxlookup for every maildomain an go through every mx record until the mail is sent succesfully or all mx records are failed. There I got some 5xx and 4xx failure codes during the transmission.
With swift I specify only the SMTP Host from the provider and there I get ony a 250 response for a successfully transmission.
If this is the answer, is it possible to setting up swift to check the maildomains?
Or is there another solution to get correct response codes and a fast transmission?
And of course I can't configure the mailserver from my provider.

Posted: Wed Apr 18, 2007 10:10 am
by Chris Corbyn
balim wrote:thanks
Sadly, i could send email to every mail address, if exists or not, and get a successful response (250).
But I've an idea what this could be.
In my own class I made a mxlookup for every maildomain an go through every mx record until the mail is sent succesfully or all mx records are failed. There I got some 5xx and 4xx failure codes during the transmission.
With swift I specify only the SMTP Host from the provider and there I get ony a 250 response for a successfully transmission.
If this is the answer, is it possible to setting up swift to check the maildomains?
Or is there another solution to get correct response codes and a fast transmission?
And of course I can't configure the mailserver from my provider.

I could write a MX verifier plugin which prevents the recipient being used if no MX record is found. I started toying with this idea a while back but got distracted. This is actually relatively trivial although it will require PHP to not be in safe_mode unless I can find out how to use sockets to query a DNS server (I tried finding the RFCs for this a while back but was overwhelmed by it).
Posted: Wed Apr 18, 2007 10:39 am
by balim
To query a DNS server, I might help you.
Here (
http://www.php.net/getmxrr) in the user comments, a user postet a mxlookup class which I'm using.
Code: Select all
<?php
class mxlookup
{
var $dns_socket = NULL;
var $QNAME = "";
var $dns_packet= NULL;
var $ANCOUNT = 0;
var $cIx = 0;
var $dns_repl_domain;
var $arrMX = array();
function mxlookup($domain, $dns="192.168.2.1")
{
$this->QNAME($domain);
$this->pack_dns_packet();
$dns_socket = fsockopen("udp://$dns", 53);
fwrite($dns_socket,$this->dns_packet,strlen($this->dns_packet));
$this->dns_reply = fread($dns_socket,1);
$bytes = stream_get_meta_data($dns_socket);
$this->dns_reply .= fread($dns_socket,$bytes['unread_bytes']);
fclose($dns_socket);
$this->cIx=6;
$this->ANCOUNT = $this->gord(2);
$this->cIx+=4;
$this->parse_data($this->dns_repl_domain);
$this->cIx+=7;
for($ic=1;$ic<=$this->ANCOUNT;$ic++)
{
$QTYPE = ord($this->gdi($this->cIx));
if($QTYPE!==15){print("[MX Record not returned]"); die();}
$this->cIx+=9;
$mxPref = ord($this->gdi($this->cIx));
$this->parse_data($curmx);
$this->arrMX[] = array("MX_Pref" => $mxPref, "MX" => $curmx);
$this->cIx+=3;
}
}
function parse_data(&$retval)
{
$arName = array();
$byte = ord($this->gdi($this->cIx));
while($byte!==0)
{
if($byte==192) //compressed
{
$tmpIx = $this->cIx;
$this->cIx = ord($this->gdi($cIx));
$tmpName = $retval;
$this->parse_data($tmpName);
$retval=$retval.".".$tmpName;
$this->cIx = $tmpIx+1;
return;
}
$retval="";
$bCount = $byte;
for($b=0;$b<$bCount;$b++)
{
$retval .= $this->gdi($this->cIx);
}
$arName[]=$retval;
$byte = ord($this->gdi($this->cIx));
}
$retval=join(".",$arName);
}
function gdi(&$cIx,$bytes=1)
{
$this->cIx++;
return(substr($this->dns_reply, $this->cIx-1, $bytes));
}
function QNAME($domain)
{
$dot_pos = 0; $temp = "";
while($dot_pos=strpos($domain,"."))
{
$temp = substr($domain,0,$dot_pos);
$domain = substr($domain,$dot_pos+1);
$this->QNAME .= chr(strlen($temp)).$temp;
}
$this->QNAME .= chr(strlen($domain)).$domain.chr(0);
}
function gord($ln=1)
{
$reply="";
for($i=0;$i<$ln;$i++){
$reply.=ord(substr($this->dns_reply,$this->cIx,1));
$this->cIx++;
}
return $reply;
}
function pack_dns_packet()
{
$this->dns_packet = chr(0).chr(1).
chr(1).chr(0).
chr(0).chr(1).
chr(0).chr(0).
chr(0).chr(0).
chr(0).chr(0).
$this->QNAME.
chr(0).chr(15).
chr(0).chr(1);
}
}
?>
Code: Select all
<?php
/* Exampe of use: */
$mx = new mxlookup("php.net");
print $mx->ANCOUNT." MX Records\n";
print "Records returned for ".$mx->dns_repl_domain.":\n<pre>";
print_r($mx->arrMX);
?>
Code: Select all
Return:
02 MX Records Records returned for php.net:
Array
(
[0] => Array
(
[MX_Pref] => 15
[MX] => smtp.osuosl.org
)
[1] => Array
(
[MX_Pref] => 5
[MX] => osu1.php.net
)
)
Posted: Wed Apr 18, 2007 10:58 am
by Chris Corbyn
Thank you

I'll disect the hell out of that until I understand it. I knew it wasn't as simple as issuing plain-text commands.
I should be able to make a plugin anyway

return-path
Posted: Fri Apr 20, 2007 3:51 am
by ollip1
Hi!
I use return-path like this
Code: Select all
$message = new Swift_Message($subject);
$message->setReturnPath($brokenaddr);
This makes the following to the header of the email
Code: Select all
Return-path: <brokenemail.address@domain.com>
I read brokenemail.address and see to whom it was sent and tag that address broken. Maybe little bit complicated but anyhow all broken emails are caught. I quess checking the address against before sending gives easier access to addresses that are not there.
Only problem at the moment is that I cannot deliver to all valid addresses. E.g. to my own gmail address may give once a while error:
Code: Select all
unrouteable mail domain "gmail.com"
I think the problem lies in the mail server, not in swift in my case.
Posted: Fri Apr 20, 2007 6:01 am
by Chris Corbyn
Messages like that come back from the SMTP server rather than Swift yes. In fact most of the error messages contain some text from the server to make it easier to identify issues
Checking domains is not enough to verify an email will be delivered. The user may not exist so you still need a bounce-detect address as ollip1 says

Posted: Fri Apr 20, 2007 9:08 am
by balim
Hmm
At the moment I handle this without a bounce-detect address and it works (slow, but it works

).
The only problem is the speed
I check the domain for MX records, connect to an existing record and start the transfer.
There I get all failure codes. Also the "user doesn't exists" code.
Is there no chance to speed up this process with swift?
If no, I have to roll up my code and create such an address. *sigh*
Posted: Fri Apr 20, 2007 1:37 pm
by Weirdan
balim wrote:Hmm
I check the domain for MX records, connect to an existing record and start the transfer.
There I get all failure codes. Also the "user doesn't exists" code.
Is there no chance to speed up this process with swift?
You could write custom smtp transport for swift, say Swift_SMTP_Direct, which would do what you described on its own.
Posted: Fri Apr 20, 2007 2:57 pm
by Chris Corbyn
Weirdan wrote:balim wrote:Hmm
I check the domain for MX records, connect to an existing record and start the transfer.
There I get all failure codes. Also the "user doesn't exists" code.
Is there no chance to speed up this process with swift?
You could write custom smtp transport for swift, say Swift_SMTP_Direct, which would do what you described on its own.
This is true. The plugin system isn't the only way to extend Swift. Pretty much everything is abstract. The connections can be anything provided they return SMTP responses. If you snoop around the source of any of the ones other than sendmail or smtp you'll get some inspiration. I actually considered writing a connector which delivers mail direct to the MX of the address. This is almost verging on becoming a MTA in itself.
Speeding up the time it takes to get a bounce response is not really possible. Not reliably anyway; a lot of server will say goody goody to your request then send you a bounce notification later.
Posted: Mon Apr 23, 2007 4:07 am
by balim
d11wtq wrote:Not reliably anyway; a lot of server will say goody goody to your request then send you a bounce notification later.
Oh, that's good information. I don't know this until now. Then a bouce mailbox is the only way to get an accurate result, isn't it?