我正在使用PHP Mail功能发送邮件
我只需要找到邮件的状态,无论是发送还是退回
有没有办法解决这个问题
答案 0 :(得分:2)
您可以将return-path标头与特定的电子邮件地址一起使用 - 例如bounce@domain.com 之后,所有退回(未交付)的电子邮件将返回收件箱以获取bounce@domain.com
您可以通过PHP连接到此pop3收件箱并阅读所有邮件。 解析每条消息并找到(可能是通过正则表达式)错误代码和原因...
我使用此代码:
$bounce = new BounceMail();
$bounce->setDebug(false);
//create connection
$bounce->createConnection('server', 110, 'user', 'password');
//parse messages
$bounce->parseMessages();
//save parsed messages to database
$messages = $bounce->getParsedMessages();
foreach ($messages as $message_id => $message) {
/* variable $message looks like:
$message = array(
'email_address' => 'email',
'bounce_type' => 'bounce type',
'smtp_server' => 'smtp_server',
'smtp_error' => 'smtp_error',
);
*/
//save returned email to database here
}
和BounceMail类:
<?php
/*
* Depends on 'Net/POP3.php';
*/
/**
* Class BounceMail
*/
class BounceMail extends Net_POP3
{
/**
* @var array
*/
private $messages = array();
/**
* @var array
*/
private $parsed_messages = array();
/**
* @var array
*/
private $partially_parsed_messages = array();
/**
* @var array
*/
private $allowed_email_domains = array();
/**
* @var array
*/
private $allowed_email_addresses = array();
/**
* @param $host
* @param $port
* @param $username
* @param $password
* @return bool
* @throws ErrorException
*/
public function createConnection($host, $port, $username, $password)
{
if (!$this->connect($host, $port)) {
Throw new ErrorException("Error connecting to POP3 socket.");
}
if (true !== ($login = $this->login($username, $password, true))) {
Throw new ErrorException("Login failed:" . $login->getMessage());
}
if (false === ($messages = $this->getListing())) {
Throw new ErrorException("Error getting POP3 box listing.");
} else {
$this->messages = $messages;
}
return true;
}
/**
* @return bool
*/
public function parseMessages()
{
$this->newDebugMessage('PARSING ' . count($this->messages) . ' MESSAGES');
$fully_parsed = 0;
foreach ($this->messages as $message) {
$parsed_message = $this->parseMessage($message);
$email_address = $this->getEmailAddress($parsed_message);
$smtp_error = $this->getSMTPError($parsed_message);
$smtp_server = $this->getSMTPServer($parsed_message);
$bounce_type = $this->getBounceType($smtp_error);
if ($this->checkAllowedContent($parsed_message)) {
$this->newParsedMessage($message['msg_id'], $email_address, $smtp_server, $smtp_error, $bounce_type);
if (!empty($email_address) && !empty($smtp_error) && !empty($smtp_server) && !empty($bounce_type)) {
$fully_parsed++;
} elseif (!empty($email_address) && (empty($smtp_error) || empty($smtp_server) || empty($bounce_type))) {
$this->newPartiallyParsedMessage($email_address, $parsed_message, array($smtp_error, $smtp_server, $bounce_type));
}
}
}
$this->newDebugMessage('SUCCESSFULLY PARSED ' . count($this->parsed_messages) . ' MESSAGES');
$this->newDebugMessage('EVERYTHING FOUND IN ' . $fully_parsed . ' MESSAGES');
return true;
}
/**
* @return array
*/
public function getParsedMessages()
{
return $this->parsed_messages;
}
/**
* @param bool $as_text
* @return array|string
*/
public function getPartiallyParsedMessages($as_text = true)
{
if ($as_text) {
$text = '';
foreach ($this->partially_parsed_messages as $message) {
foreach ($message as $data) {
$text .= $data . "\r\n";
}
$text .= "\r\n---------------\r\n\r\n";
}
return $text;
} else {
return $this->partially_parsed_messages;
}
}
/**
* @param array $domains
*/
public function setAllowedEmailDomains(array $domains)
{
$this->allowed_email_domains = $domains;
}
/**
* @param array $addresses
*/
public function setAllowedEmailAddresses(array $addresses)
{
$this->allowed_email_addresses = $addresses;
}
/**
* @param $message
* @return bool|string
*/
public function newDebugMessage($message)
{
if ($this->_debug) {
$trace = debug_backtrace();
$debug_message = !empty($trace) && isset($trace[1]["function"]) ? $trace[1]["function"] . ' | ' : '';
$debug_message .= !empty($trace) && isset($trace[1]["method"]) ? $trace[1]["method"] . ' | ' : '';
$debug_message .= $message . "\r\n";
echo $debug_message;
return $debug_message;
}
return false;
}
/**
* @param $parsed_message
* @return bool
*/
private function checkAllowedContent($parsed_message)
{
foreach ($parsed_message as $content) {
if (!$this->parseAllowedContent($content)) {
return false;
}
}
return true;
}
/**
* @param $content
* @return bool
*/
private function parseAllowedContent($content)
{
$patterns = array(
'SENDER POLICY FRAMEWORK' => '/(5.7.1\s*Sender\s*Policy\s*Framework)/im',
'TOO MANY HOPS' => '/too\s*many\s*hops/im',
'BLOCKED' => '/554\s*Blocked\s*by\s*Reputation\s*Enabled\s*Defense/im'
);
foreach ($patterns as $name => $pattern) {
$matches = array();
preg_match($pattern, $content, $matches);
if (isset($matches[1]) && !empty($matches[1])) {
$this->newDebugMessage('DISALLOWED CONTENT FOUND (' . $name . ')');
return false;
}
}
return true;
}
/**
* @param $message_id
* @param $email_address
* @param $smtp_server
* @param $smtp_error
* @param $bounce_type
* @return array|bool
*/
private function newParsedMessage($message_id, $email_address, $smtp_server, $smtp_error, $bounce_type)
{
if (!empty($message_id) && !empty($email_address)) {
return $this->parsed_messages[$message_id] = array('email_address' => $email_address, 'smtp_server' => $smtp_server, 'smtp_error' => $smtp_error, 'bounce_type' => $bounce_type);
}
return false;
}
/**
* @param $email_address
* @param array $parsed_message
* @param array $vars
* @return array|bool
*/
private function newPartiallyParsedMessage($email_address, array $parsed_message, array $vars = array())
{
$full_content = '';
foreach ($parsed_message as $content) {
$full_content .= $content . "\r\n";
}
if (!empty($email_address) && !empty($full_content)) {
if (!empty($vars)) {
foreach ($vars as $var) {
$full_content .= "\r\n" . $var . ' | ';
}
}
return $this->partially_parsed_messages[] = array($email_address, $full_content);
} else {
return false;
}
}
/**
* @param $message
* @return array|bool
*/
private function parseMessage($message)
{
if (empty($message)) {
$this->newDebugMessage('Empty message');
return false;
}
if (!$content = $this->getMsg($message['msg_id'])) {
$this->newDebugMessage('Error reading content of message :' . $message['msg_id'] . '/' . $message['uidl']);
}
//todo add attachments
if (!empty($content)) {
return array('content' => $content);
}
return false;
}
/**
* @param $parsed_message
* @return bool
*/
private function getEmailAddress($parsed_message)
{
if (empty($parsed_message)) {
$this->newDebugMessage('Empty parsed message');
return false;
}
$found_emails = array();
foreach ($parsed_message as $content) {
$found_emails = array_unique(array_merge($found_emails, $this->parseEmailAddress($content)));
}
if (count($found_emails) > 1) {
$this->newDebugMessage('More than one e-mail address found: ' . join('; ', $found_emails));
return false;
}
if (count($found_emails) == 1) {
$this->newDebugMessage('Found e-mail address: ' . $found_emails[0]);
return $found_emails[0];
}
$this->newDebugMessage('No e-mail address found');
return false;
}
/**
* @param $content
* @return array
*/
private function parseEmailAddress($content)
{
$email_patterns = array('/[^-]To:\s?<?([a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+)>?/i',);
$found_emails = array();
foreach ($email_patterns as $pattern) {
$matches = array();
preg_match_all($pattern, $content, $matches);
if (!empty($matches) && isset($matches[1])) {
$recipient_emails = $matches[1];
$recipient_emails = array_filter($recipient_emails, array($this, 'filter_allowed_domains'));
$recipient_emails = array_filter($recipient_emails, array($this, 'filter_allowed_addresses'));
if (!empty($recipient_emails)) {
$found_emails = array_unique(array_merge($found_emails, $recipient_emails));
}
}
}
return $found_emails;
}
/**
* @param $email
* @return bool
*/
private function filter_allowed_domains($email)
{
return !in_array(substr(strrchr($email, "@"), 1), $this->allowed_email_domains);
}
/**
* @param $email
* @return bool
*/
private function filter_allowed_addresses($email)
{
return !in_array($email, $this->allowed_email_addresses);
}
/**
* @param $smtp_error
* @return bool|int
*/
private function getBounceType($smtp_error)
{
if (empty($smtp_error)) {
$this->newDebugMessage('Empty smtp error');
return false;
}
$status = substr($smtp_error, 0, 1);
switch ($status) {
case 4:
return 1; //temporary
break;
case 5:
return 2; //permanent
break;
}
return false;
}
/**
* @param $parsed_message
* @return bool
*/
private function getSMTPServer($parsed_message)
{
if (empty($parsed_message)) {
$this->newDebugMessage('Empty parsed message');
return false;
}
$found = array();
foreach ($parsed_message as $content) {
$found = array_unique(array_merge($found, $this->parseSMTPServer($content)));
}
if (count($found) > 0) {
$server = substr(join('; ', $found), 0, 254);
$this->newDebugMessage('Found SMTP server: ' . $server);
return $server;
}
$this->newDebugMessage('No SMTP server found');
return false;
}
/**
* @param $content
* @return array
*/
private function parseSMTPServer($content)
{
$patterns = array('/remote-mta:\s?dns;\s?([^\s]*)/i', '/reporting-mta:\s?dns;\s?([^\s]*)/i', '/received-from-mta:\s?dns;\s?([^\s]*)/i');
$found_statuses = array();
foreach ($patterns as $pattern) {
$matches = array();
preg_match_all($pattern, $content, $matches);
if (!empty($matches) && isset($matches[1])) {
$found_statuses = array_unique(array_merge($found_statuses, $matches[1]));
}
}
return $found_statuses;
}
/**
* @param $parsed_message
* @return bool
*/
private function getSMTPError($parsed_message)
{
if (empty($parsed_message)) {
$this->newDebugMessage('Empty parsed message');
return false;
}
$found = array();
foreach ($parsed_message as $content) {
$found = array_unique(array_merge($found, $this->parseSMTPError($content)));
}
if (count($found) > 0) {
$error = substr(join('; ', $found), 0, 19);
$this->newDebugMessage('Found SMTP Error: ' . $error);
return $error;
}
$this->newDebugMessage('No SMTP Error found');
return false;
}
/**
* @param $content
* @return array
*/
private function parseSMTPError($content)
{
//replace errors with codes
$content = str_replace('User mailbox exceeds allowed size', ' 452 4.1.1 ', $content);
$content = str_replace('user is over quota', ' 452 4.1.1 ', $content);
//find error
$patterns = array(
'/status:\s?#?(\d\.\d\.\d)/i',
'/[\d]{3}\s#?(\d\.\d\.\d)/',
'/\(#(\d\.\d\.\d)\)/',
'/Remote SMTP Server Returned:\s?#?([\d]{3})/i',
);
$found_statuses = array();
foreach ($patterns as $pattern) {
$matches = array();
preg_match_all($pattern, $content, $matches);
if (!empty($matches) && isset($matches[1])) {
$found_statuses = array_unique(array_merge($found_statuses, $matches[1]));
}
}
return $found_statuses;
}
}
你应该在parseSMTPError中添加更多的常规