| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| PHP mail() | 零依賴、內建 | 功能弱、易進垃圾箱、無 SMTP 驗證 | 簡單通知、開發測試 |
| SMTP 類別 (自寫/PEAR) | 可控性高、支援驗證、SSL/TLS | 需自行處理 MIME、編碼、附件 | 學習、輕量專案 |
| PHPMailer / Symfony Mailer | 功能完整、安全、支援異步、模板 | 需 Composer 安裝 | 生產環境首選 |
| API 服務 | 送達率高、統計分析、免維護 | 成本、資料外洩風險 | 行銷郵件、交易郵件大量發送 |
原文提供的 JMail 為 ASP/COM 組件,PHP 環境無法直接使用。此處保留參考,實務請改用 PHP 原生方案。
<?php
class SmtpMailer {
private $host;
private $port;
private $username;
private $password;
private $timeout = 30;
private $socket;
public function __construct(string $host, int $port = 587, string $username = '', string $password = '') {
$this->host = $host;
$this->port = $port;
$this->username = $username;
$this->password = $password;
}
public function send(string $to, string $from, string $subject, string $body, bool $isHtml = true, array $options = []): bool {
if (!$this->connect()) return false;
if (!$this->auth()) { $this->close(); return false; }
if (!$this->mailFrom($from)) { $this->close(); return false; }
if (!$this->rcptTo($to)) { $this->close(); return false; }
if (!$this->data($from, $to, $subject, $body, $isHtml)) { $this->close(); return false; }
$this->close();
return true;
}
private function connect(): bool {
$this->socket = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout);
if (!$this->socket) return false;
return $this->readResponse(220);
}
private function auth(): bool {
if (!$this->username) return true; // 無驗證模式
fwrite($this->socket, "AUTH LOGIN\r\n");
if (!$this->readResponse(334)) return false;
fwrite($this->socket, base64_encode($this->username) . "\r\n");
if (!$this->readResponse(334)) return false;
fwrite($this->socket, base64_encode($this->password) . "\r\n");
return $this->readResponse(235);
}
private function mailFrom(string $from): bool {
fwrite($this->socket, "MAIL FROM:<$from>\r\n");
return $this->readResponse(250);
}
private function rcptTo(string $to): bool {
fwrite($this->socket, "RCPT TO:<$to>\r\n");
return $this->readResponse(250);
}
private function data(string $from, string $to, string $subject, string $body, bool $isHtml): bool {
fwrite($this->socket, "DATA\r\n");
if (!$this->readResponse(354)) return false;
$headers = [
"From: $from",
"To: $to",
"Subject: $subject",
"Date: " . date('r'),
"MIME-Version: 1.0",
"Content-Type: " . ($isHtml ? 'text/html' : 'text/plain') . "; charset=UTF-8",
"X-Mailer: PHP/" . phpversion(),
];
if (!empty($options['cc'])) $headers[] = "Cc: " . implode(', ', $options['cc']);
if (!empty($options['bcc'])) $headers[] = "Bcc: " . implode(', ', $options['bcc']);
$message = implode("\r\n", $headers) . "\r\n\r\n" . $body . "\r\n.\r\n";
fwrite($this->socket, $message);
return $this->readResponse(250);
}
private function readResponse(int $expectedCode): bool {
$response = fgets($this->socket, 512);
return (int)substr($response, 0, 3) === $expectedCode;
}
private function close(): void {
if ($this->socket) {
@fwrite($this->socket, "QUIT\r\n");
@fclose($this->socket);
$this->socket = null;
}
}
}
// 使用範例
$mailer = new SmtpMailer('smtp.gmail.com', 587, 'user@gmail.com', 'app_password');
$ok = $mailer->send(
'recipient@example.com',
'sender@example.com',
'測試主旨',
'HTML 內容
支援中文
',
true
);
echo $ok ? '發送成功' : '發送失敗';
?>
<?php
// composer require phpmailer/phpmailer
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require 'vendor/autoload.php';
$mail = new PHPMailer(true);
try {
$mail->isSMTP();
$mail->Host = 'smtp.gmail.com';
$mail->SMTPAuth = true;
$mail->Username = 'user@gmail.com';
$mail->Password = 'app_password';
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; // 或 ENCRYPTION_SMTPS (465)
$mail->Port = 587;
$mail->setFrom('sender@example.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');
$mail->isHTML(true);
$mail->Subject = 'PHPMailer 測試';
$mail->Body = 'HTML 內容
支援中文、附件、內嵌圖片
';
$mail->AltBody = '純文字備用內容';
$mail->send();
echo '發送成功';
} catch (Exception $e) {
echo "發送失敗:{$mail->ErrorInfo}";
}
?>
// 生產者:寫入佇列
$redis->lpush('mail_queue', json_encode([
'to' => 'user@example.com',
'subject' => '歡迎註冊',
'template' => 'welcome',
'data' => ['name' => 'John']
]));
// 消費者:背景工作處理
while (true) {
$job = $redis->brpop('mail_queue', 5);
if ($job) {
$data = json_decode($job[1], true);
// 渲染模板 -> PHPMailer 發送
}
}
?>
PHP 發送郵件已從早期 mail()、自寫 SMTP 類別演進至 PHPMailer/Symfony Mailer 等成熟函式庫。生產環境務必配合 SPF/DKIM/DMARC、非同步佇列、退信處理、內容優化,才能獲得高送達率與可維護的郵件系統。