首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 發送郵件兩大方案:內建 mail() vs SMTP 類別完整比較

     編輯:PHP 綜合知識

PHP 發送郵件主要有兩條路:使用內建 mail() 函式,或引入 SMTP 協定類別(如 PHPMailer、Symfony Mailer)。本文深度比較兩者優缺點、適用場景與完整實作範例。

方案一:內建 mail() 函式

基本用法

<?php
$to = 'user@example.com';
$subject = '測試郵件';
$message = '這是一封測試郵件內容。';
$headers = "From: sender@example.com\r\n" .
           "Reply-To: reply@example.com\r\n" .
           "Content-Type: text/plain; charset=UTF-8\r\n" .
           "X-Mailer: PHP/" . phpversion();

mail($to, $subject, $message, $headers);
?>

必要條件:本地 MTA (Mail Transfer Agent)

mail() 只是將郵件交給本機 MTA(如 Sendmail、Postfix、Exim),不支援 SMTP 認證。因此:

  • 伺服器必須安裝並正確設定 MTA
  • 無法直接使用 Gmail、Outlook、企業郵件伺服器(需 SMTP 認證)
  • 郵件易被判定為垃圾郵件(缺乏 SPF/DKIM/DMARC 簽名)
  • Windows 環境極難設定

php.ini 設定(僅適用本機 MTA)

; Linux/Unix (使用 sendmail)
sendmail_path = "/usr/sbin/sendmail -t -i"

; Windows (需指定 SMTP 伺服器,但不支援認證)
SMTP = localhost
smtp_port = 25
sendmail_from = me@example.com

方案二:SMTP 類別(推薦:PHPMailer / Symfony Mailer)

為什麼選 SMTP 類別?

特性mail()SMTP 類別
SMTP 認證❌✅
SSL/TLS 加密❌✅
HTML 郵件手動組裝✅ 內建
附件支援手動組裝✅ 內建
嵌入圖片極困難✅ 內建
多收件人/抄送/密件副本手動處理✅ 內建
郵件佇列/批次發送❌✅ 支援
錯誤處理/除錯極少✅ 詳細
跨平台相容差✅ 純 PHP

PHPMailer 完整實作(最流行、最成熟)

composer require phpmailer/phpmailer
<?php
require 'vendor/autoload.php';

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;

$mail = new PHPMailer(true);  // true = 啟用例外處理

try {
    // === SMTP 伺服器設定 ===
    $mail->isSMTP();
    $mail->Host       = 'smtp.gmail.com';      // SMTP 伺服器
    $mail->SMTPAuth   = true;                  // 啟用認證
    $mail->Username   = 'your@gmail.com';      // 帳號
    $mail->Password   = 'your_app_password';   // 應用程式密碼(非登入密碼)
    $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; // TLS
    $mail->Port       = 587;                   // TLS 埠口
    // $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS; // SSL
    // $mail->Port       = 465;                 // SSL 埠口

    // === 寄件人/收件人 ===
    $mail->setFrom('your@gmail.com', '您的名稱');
    $mail->addAddress('recipient@example.com', '收件人名稱');
    $mail->addReplyTo('reply@example.com', '回覆地址');
    $mail->addCC('cc@example.com');
    $mail->addBCC('bcc@example.com');

    // === 附件 ===
    $mail->addAttachment('/path/to/file.pdf', 'rename.pdf');
    $mail->addAttachment('/path/to/image.jpg');  // 檔名保持原狀

    // === 內容 ===
    $mail->isHTML(true);  // 設定為 HTML 格式
    $mail->Subject = 'PHPMailer 測試郵件';
    $mail->Body    = '<h1>HTML 內容</h1><p>支援 <b>粗體</b>、連結、圖片等。</p>';
    $mail->AltBody = '純文字備用內容(不支援 HTML 的郵件客戶端)';

    // === 嵌入圖片 (CID) ===
    $mail->addEmbeddedImage('/path/to/logo.png', 'logo_id');
    $mail->Body = '<img src="cid:logo_id" alt="Logo">' . $mail->Body;

    $mail->send();
    echo '郵件發送成功!';
} catch (Exception $e) {
    echo "發送失敗: {$mail->ErrorInfo}";
}
?>

Gmail / Outlook / 企業郵件 設定對照

提供商SMTP 主機埠口加密帳號/密碼
Gmailsmtp.gmail.com587 (TLS) / 465 (SSL)STARTTLS / SSL需開啟「應用程式密碼」
Outlook/Hotmailsmtp.office365.com587STARTTLS完整信箱 / 登入密碼
Yahoosmtp.mail.yahoo.com465/587SSL/TLS需開啟「應用程式密碼」
企業 Exchangesmtp.公司域名.com587STARTTLS完整信箱 / AD 密碼
SendGridsmtp.sendgrid.net587/2525/465TLS/SSLapikey / API Key
Mailgunsmtp.mailgun.org587/2525TLSpostmaster@域名 / API Key

Symfony Mailer (現代替代方案,Laravel 預設)

composer require symfony/mailer
<?php
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mailer\Transport;
use Symfony\Component\Mime\Email;

$dsn = 'smtp://user:pass@smtp.gmail.com:587';
$transport = Transport::fromDsn($dsn);
$mailer = new Mailer($transport);

$email = (new Email())
    ->from('your@gmail.com')
    ->to('recipient@example.com')
    ->subject('Symfony Mailer 測試')
    ->html('<h1>HTML 內容</h1>')
    ->text('純文字內容')
    ->attachFromPath('/path/to/file.pdf');

$mailer->send($email);
?>

進階主題

1. 批次發送與佇列

<?php
// PHPMailer 批次發送(重複使用 SMTP 連線)
$mail = new PHPMailer(true);
$mail->isSMTP();
$mail->Host = 'smtp.gmail.com';
// ... 設定 SMTP ...

$mail->setFrom('sender@example.com');
$mail->Subject = '批次通知';
$mail->Body = '通知內容...';

$recipients = [
    ['email' => 'a@example.com', 'name' => 'User A'],
    ['email' => 'b@example.com', 'name' => 'User B'],
    // ...
];

// 保持連線開啟
$mail->SMTPKeepAlive = true;

foreach ($recipients as $rcpt) {
    $mail->clearAddresses();
    $mail->addAddress($rcpt['email'], $rcpt['name']);
    try {
        $mail->send();
        echo "Sent to {$rcpt['email']}\n";
    } catch (Exception $e) {
        echo "Failed to {$rcpt['email']}: {$mail->ErrorInfo}\n";
    }
}
// 記得關閉連線
$mail->smtpClose();
?>

2. 非同步發送(避免阻塞回應)

  • Laravel Queue + Symfony Mailer
  • RabbitMQ / Redis 佇列 + 背景 Worker
  • 簡易做法:exec("php send_mail.php > /dev/null 2>&1 &")(不推薦生產環境)

3. 郵件送達率優化清單

  1. 設定 SPF、DKIM、DMARC DNS 記錄
  2. 使用專業郵件服務
  3. 避免垃圾郵件關鍵字、過多連結、全大寫標題
  4. 提供退訂連結
  5. 監控退信率、投訴率
  6. 使用專屬 IP 或共用信譽良好的 IP 池

總結建議

場景推薦方案
簡單通知、內部系統、已有 MTAmail() 可接受
對外發送、需 HTML/附件、生產環境PHPMailer / Symfony Mailer
大量行銷郵件、交易郵件SendGrid, Mailgun, Amazon SES + SDK
Laravel / Symfony 專案Symfony Mailer (內建整合)

結論:現代 PHP 專案強烈建議直接使用 PHPMailer 或 Symfony Mailer,避開 mail() 的諸多限制與坑。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved