2009-05-01 184 views
16

我有點擔心,如果這個功能將能夠正確地對多數電子郵件和網絡郵件客戶端的方式應該得到承認的郵件,特別是我最關心這個疑惑:這是用PHP發送電子郵件的正確方法嗎?

  • 是UTF -8聲明和附件是否形成良好?
  • 我需要使用quoted_printable_decode()嗎?如果是,在哪裏?
  • 內容傳輸編碼:7或8位?我一直看到7,但因爲我發送一個UTF-8編碼的郵件,我不確定。
  • 我應該使用mb_send_mail()還是mail()就夠了?

編輯:我不知道爲什麼,但代碼顯示不正確,我將其提供@http://gist.github.com/104818

編輯2:我知道其他替代品(庫)的電子郵件處理,但爲了我自己的好奇心和知識,我只想知道這段代碼是否100%好,或者它是否有問題。

function Email($name, $from, $to, $subject, $message, $bcc = null, $attachments = null) 
{ 
    ini_set('SMTP', 'localhost'); 
    ini_set('sendmail_from', $from); 

    $name = filter_var($name, FILTER_SANITIZE_STRING); 
    $from = filter_var($from, FILTER_SANITIZE_EMAIL); 
    $subject = filter_var($subject, FILTER_SANITIZE_STRING); 

    $boundary = '_Boundary_' . md5(microtime(true) . mt_rand(0, PHP_INT_MAX)); 

    $headers = array 
    (
     'MIME-Version: 1.0', 
     'Content-Type: multipart/mixed; boundary="Mixed' . $boundary . '"', 
     'Date: ' . date('r', time()), 
     'From: "' . $name . '" <' . $from . '>', 
     'Reply-To: "' . $name . '" <' . $from . '>', 
     'Return-Path: "' . $name . '" <' . $from . '>', 
     'X-Mailer: PHP ' . phpversion(), 
     'X-Priority: 2', 
     'X-MSMail-Priority: High', 
     'X-Originating-IP: ' . $_SERVER['SERVER_ADDR'], 
    ); 

    if (is_null($to) === false) 
    { 
     if (is_array($to) === false) 
     { 
      $to = explode(',', $to); 
     } 

     foreach ($to as $key => $value) 
     { 
      $to[$key] = filter_var($value, FILTER_SANITIZE_EMAIL); 
     } 

     $to = implode(', ', array_filter($to)); 
    } 

    if (is_null($bcc) === false) 
    { 
     if (is_array($bcc) === false) 
     { 
      $bcc = explode(',', $bcc); 
     } 

     foreach ($bcc as $key => $value) 
     { 
      $bcc[$key] = filter_var($value, FILTER_SANITIZE_EMAIL); 
     } 

     $headers[] = 'BCC: ' . implode(', ', array_filter($bcc)); 
    } 

    if (is_null($attachments) === false) 
    { 
     settype($attachments, 'array'); 

     foreach ($attachments as $key => $value) 
     { 
      if (is_file($value) === true) 
      { 
       $attachments[$key] = array 
       (
        '', 
        '--Mixed' . $boundary, 
        'Content-Type: application/octet-stream; name="' . basename($value) . '"', 
        'Content-Disposition: attachment; filename="' . basename($value) . '"', 
        'Content-Transfer-Encoding: base64', 
        '', 
        trim(chunk_split(base64_encode(file_get_contents($value)))), 
       ); 

       $attachments[$key] = implode("\n", $attachments[$key]); 
      } 

      else 
      { 
       unset($attachments[$key]); 
      } 
     } 

     $attachments = implode("\n", $attachments) . "\n"; 
    } 

    $message = array 
    (
     'This is a multi-part message in MIME format.', 
     '', 
     '--Mixed' . $boundary, 
     'Content-Type: multipart/alternative; boundary="Alt' . $boundary . '"', 
     '', 
     '--Alt' . $boundary, 
     'Content-Type: text/plain; charset="UTF-8"', 
     'Content-Disposition: inline', 
     'Content-Transfer-Encoding: 8bit', 
     '', 
     trim(strip_tags($message, '<a>')), 
     '', 
     '--Alt' . $boundary, 
     'Content-Type: text/html; charset="UTF-8"', 
     'Content-Disposition: inline', 
     'Content-Transfer-Encoding: 8bit', 
     '', 
     trim($message), 
     '', 
     '--Alt' . $boundary . '--', 
     $attachments, 
     '--Mixed' . $boundary . '--', 
    ); 

    if (@mail($to, stripslashes($subject), implode("\n", $message), implode("\n", $headers)) === true) 
    { 
     return true; 
    } 

    return false; 
} 

回答

27

雖然這應該工作,我會強烈建議使用預置的郵件/ SMTP類如Zend_Mail。雖然我不認爲整個Zend Framework是貓的睡衣,但我對他們的郵件處理代碼有非常好的看法。

編輯:我還應該補充說,使用預建的郵件/ SMTP類將會抽象出幾乎所有的複雜性/多部分電子郵件的結構。

更新2009-05-06:直接回答你的問題。

  • 是UTF-8的聲明和附件以及怎樣形成的?

他們看起來不錯。

  • 我需要使用quoted_printable_decode()?如果是,在哪裏?

號,您可能需要使用quoted_printable_decode()僅當您解碼的電子郵件。不是當你編碼一個。你應該使用quoted_printable_encode()?接下來我將討論這個問題。

  • Content-Transfer-Encoding:7或8位?我一直看到7,但因爲我發送一個UTF-8編碼的郵件,我不確定。

僅使用8位編碼,如果你知道目標SMTP服務器能夠支持。但是,由於您將電子郵件傳遞給本地MTA,因此我不建議設置此值。默認值是7位編碼,但它有它自己的一套限制:代碼範圍1-127的每行最多998個八位字節,CR和LF只允許作爲CRLF行結尾的一部分出現(http://tools.ietf.org/html/rfc2045#section-2.7)。

我建議你使用Quoted-Printable(http://tools.ietf.org/html/rfc2045#section-6.7)Content-Transfer-Encoding。如果您要撥打trim(strip_tags($message, '<a>'))trim($message),您需要附上quoted_printable_encode(trim(...))

  • 我應該使用mb_send_mail()mail()夠嗎?

如果你知道你是不是要處理的多字節消息(日語,韓語,中國等),則mail()應該足夠了。

現在我已經回答了您最初的問題,讓我告訴您存在哪些問題。

  1. 您指定純文本和Html內容部分的字符集是UTF-8,但它並未顯示,因爲您實際上確保它們確實是UTF-8編碼。
  2. 您在$to檢查null$bcc,​​之前進一步處理它們,但是,你沒有做任何事情時,他們實際上可能是null。因此,如果您碰巧收到$tonull,則不會處理該變量,但您會繼續發送電子郵件至null

從現在開始,這就是我將要進入的一切,但我仍然強烈建議使用預先構建的解決方案,因爲他們有很多用戶/時間去處理錯誤。

+0

血腥的好回答瓊斯先生。我希望你得到賞金+1 – da5id 2009-05-08 00:19:47

+1

我同意,Zend_Mail擁有你需要的一切和更多!使用由許多人開發的庫,它通常具有較少的錯誤。 – Kekoa 2009-05-11 15:43:58

17

我在大多數情況下都是自己動手的,但是當談到郵件時,我會衷心推薦讓自己更容易,並使用像Swift MailerPHPMailer(依次爲我的錢) 。

作爲一個附加獎勵(並假設您指定回覆等),您也很少有機會被標記爲垃圾郵件。