2013-08-02 37 views
0

我送使用PHP郵件功能
我只需要找到該郵件的狀態,無論是交付或退回
郵件有沒有解決這個任何可能的方式未發送郵件ID退回或問題如何找到使用PHP

+2

好的,祝你好運。 (即,這看起來更像是一個聲明,如果你不提供詳細信息/帶有特定問題,我們不能幫你) – AmazingDreams

回答

2

您可以使用返回路徑頭與特定的電子郵件地址 - 例如[email protected] 之後,所有的反彈(未交付)的電子郵件將返回到收件箱[email protected]

您可以通過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_.-][email protected][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; 
    } 
} 

你應該增加更多regulars into parseSMTPError

+0

我發送的每封郵件都將存儲在數據庫中
我只需要只有狀態「失敗」或「成功」 – coolprarun

+1

您必須監控未發送的退回電子郵件。如果您發送電子郵件,您不知道它是否已交付,直到您有(或沒有)返回的電子郵件 – emte

+0

是否有任何腳本直接寫入失敗消息到數據庫,以便我可以查看所有狀態單地方@emte – coolprarun