Decoding the failing recipient from the bounce email
Now that the mail is successfully in the PHP script, our task will be to extract the failing recipient from the encoded email headers. Thanks to exim configurations like envelope_to_add in the pipe transport (above), the VERP address gets pasted to the To header of the bounce email, and that’s the place to look for the failing recipient.
Some common regex functions to extract the headers are: function extractHeaders( $email ) { $bounceHeaders = array(); $lineBreaks = explode( "\n", $email ); foreach ( $lineBreaks as $lineBreak ) {
if ( preg_match( "/^To: (.*)/", $lineBreak , $toMatch )
){
$bounceHeaders[ 'to' ] = $toMatch[1]; } if ( preg_match( "/^Subject: (.*)/", $lineBreak , $subjectMatch ) ) {
$bounceHeaders[ 'subject' ] = $subjectMatch[1]; } if ( preg_match( "/^Date: (.*)/", $lineBreak , $dateMatch ) ) {
$bounceHeaders[ 'date' ] = $dateMatch[1]; } if ( trim( $lineBreak ) == "" ) {
// Empty line denotes that the header part is
finished
break;
} } return $bounceHeaders;
}
After extracting the headers, we need to decode the original-failed-recipient email ID from the VERP hashed $bounceHeader[‘ to’], which involves more or less the reverse of what we did earlier. This would help us validate the bounced email too. /** *Considering the recieved $heders[ ‘to’ ] is of the form * bounces-{ to_address }-{ delivery_timestamp }-{ encode ( to_address-delivery & timestamp ), * secretKey }@ somewhere.com
*/ $hashedTo = $headers[ ‘to’ ]’;
$to = self::extractToAddress( $hashedTo ); function extractToAddress( $hashedTo ) {
$timeNow = time();
// This will help us get the address part of address@ domain
preg_match( '~(.*?)@~', $hashedTo, $hashedSlice );
// This will help us cut the address part with the symbol ‘ - ‘ $hashedAddressPart = explode( '-', $hashedSlice1] ); // Now we have the prefix in $hashedAddressPart[ 0 - 2 ] and the hash in $hashedAddressPart[3]
$verpPrefix = $hashedAddressPart [0]. '-'. $hashedAddressPart 1]. '-'. hashedAddressPart [2]; // Extracting the bounce time. $bounceTime = $hashedAddressPart[ 2 ];
// Valid time for a bounce to happen. The values can be subtracted to find out the time in between and even used to set an accept time, say 3 days. if ( $bounceTime < $timeNow ) {
if ( hash_hmac( $hashAlgorithm, $verpPrefix , $hashSecretKey ) === $hashedAddressPart[3] ) {
// Bounce is valid, as
the comparisons return true.
$to = string_replace(
‘.’, ‘@’, $verpPrefix[1] );
return $to;
} } }