PHP 發送郵件主要有三條路:mail() 系統函數(簡單但進垃圾箱率高)、SMTP 直連(需自建/租用郵件服務器)、第三方 API(SendGrid、郵件推送服務、騰訊雲/阿里雲簡訊郵件)。本文提供SMTP 通用發信類與第三方 HTTP API 調用兩套生產可用代碼。
<?php
class SmtpMailer {
private $host, $port, $username, $password, $fromName, $timeout = 30;
private $socket;
public function __construct($host, $port, $username, $password, $fromName = '') {
$this->host = $host; $this->port = $port;
$this->username = $username; $this->password = $password;
$this->fromName = $fromName ?: $username;
}
public function send($to, $subject, $bodyHtml, $bodyText = '', $attachments = []) {
$this->connect();
$this->auth();
$this->mailFrom();
$this->rcptTo($to);
$this->data($subject, $bodyHtml, $bodyText, $attachments);
$this->quit();
$this->close();
return true;
}
private function connect() {
$this->socket = @stream_socket_client(
"tcp://{$this->host}:{$this->port}",
$errno, $errstr, $this->timeout
);
if (!$this->socket) throw new \Exception("Connect failed: $errstr ($errno)");
$this->readResponse(220);
$this->write("EHLO " . gethostname());
$this->readResponse(250);
}
private function auth() {
$this->write("AUTH LOGIN");
$this->readResponse(334);
$this->write(base64_encode($this->username));
$this->readResponse(334);
$this->write(base64_encode($this->password));
$this->readResponse(235);
}
private function mailFrom() {
$this->write("MAIL FROM:<{$this->username}>");
$this->readResponse(250);
}
private function rcptTo($to) {
foreach ((array)$to as $addr) {
$this->write("RCPT TO:<$addr>");
$this->readResponse(250);
}
}
private function data($subject, $html, $text, $attachments) {
$this->write("DATA");
$this->readResponse(354);
$boundary = "----PHP_SMTP_" . md5(time());
$headers = [
"From: {$this->fromName} <{$this->username}>",
"To: " . implode(', ', (array)$to),
"Subject: =?UTF-8?B?" . base64_encode($subject) . "?=",
"MIME-Version: 1.0",
"Content-Type: multipart/alternative; boundary=\"$boundary\"",
"",
"--$boundary",
"Content-Type: text/plain; charset=UTF-8",
"Content-Transfer-Encoding: base64",
"",
base64_encode($text ?: strip_tags($html)),
"--$boundary",
"Content-Type: text/html; charset=UTF-8",
"Content-Transfer-Encoding: base64",
"",
base64_encode($html),
"--$boundary--",
"."
];
foreach ($headers as $line) $this->write($line);
$this->readResponse(250);
}
private function write($line) {
fwrite($this->socket, $line . "\r\n");
}
private function readResponse($expectCode = null) {
$response = '';
while ($str = fgets($this->socket, 512)) {
$response .= $str;
if (preg_match('/^\d{3} /', $str)) break;
}
if ($expectCode && !preg_match("/^{$expectCode}/", $response)) {
throw new \Exception("SMTP Error: $response");
}
return $response;
}
private function quit() { $this->write("QUIT"); $this->readResponse(221); }
private function close() { if ($this->socket) fclose($this->socket); }
}
// 使用示例(QQ 郵箱 SMTP)
$mailer = new SmtpMailer('smtp.qq.com', 465, 'your@qq.com', 'auth_code', '我的應用');
$mailer->send('target@example.com', '測試主題', '<h1>HTML 內容</h1>', '純文本備用');
?>
注意:QQ/163/GMail 等需開啟「SMTP 服務」並生成授權碼(非登錄密碼),端口 465 (SSL) 或 587 (TLS)。
<?php
function sendMailApi($to, $subject, $html, $config) {
$url = $config['api_url']; // 如 https://api.sendgrid.com/v3/mail/send
$data = [
'personalizations' => [[
'to' => [['email' => $to]],
'subject' => $subject
]],
'from' => ['email' => $config['from_email'], 'name' => $config['from_name']],
'content' => [
['type' => 'text/html', 'value' => $html]
]
];
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $config['api_key'],
'Content-Type: application/json'
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_SSL_VERIFYPEER => true
]);
$resp = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $code >= 200 && $code < 300;
}
// 配置示例
$config = [
'api_url' => 'https://api.sendgrid.com/v3/mail/send',
'api_key' => 'SG.xxxxx',
'from_email' => 'noreply@myapp.com',
'from_name' => 'MyApp'
];
sendMailApi('user@example.com', '歡迎註冊', '<p>內容</p>', $config);
?>
multipart/mixed 部分,Base64 編碼文件內容RCPT TO 多次調用,Header 添加 Cc:/Bcc:List-Unsubscribe Header,合規且減少投訴無論選擇 SMTP 直連還是 API,核心是可靠投遞、合規合法、可觀測。建議生產環境優先使用成熟的第三方郵件服務(SendGrid、Mailgun、騰訊雲郵件推送),專注業務邏輯而非郵件服務器運維。