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

PHP 發送郵件實戰:基於 SMTP 協議的通用發信類封裝與第三方 API 調用示例

     編輯:PHP 相關知識

PHP 發送郵件實戰:基於 SMTP 協議的通用發信類封裝與第三方 API 調用示例

PHP 發送郵件主要有三條路:mail() 系統函數(簡單但進垃圾箱率高)、SMTP 直連(需自建/租用郵件服務器)、第三方 API(SendGrid、郵件推送服務、騰訊雲/阿里雲簡訊郵件)。本文提供SMTP 通用發信類與第三方 HTTP API 調用兩套生產可用代碼。

一、SMTP 直連發信類(基於 fsockopen/stream_socket_client)

<?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)。

二、第三方 HTTP API 發信(以騰訊雲/阿里雲/SendGrid 為例)

<?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);
?>

三、進階功能:附件、抄送、模板、異步隊列

  • 附件:SMTP DATA 階段添加 multipart/mixed 部分,Base64 編碼文件內容
  • 抄送/密送:RCPT TO 多次調用,Header 添加 Cc:/Bcc:
  • 模板引擎:集成 Twig/Blade,渲染 HTML 再發送
  • 異步發送:將發信任務推入 Redis/RabbitMQ/Swoole Task,Worker 消費重試、限流、日誌
  • 退信/打開追蹤:配置 Webhook 接收郵件服務商回調

四、避坑指南

  1. 發信域名配置 SPF、DKIM、DMARC 記錄,極大降低進垃圾箱率
  2. 新域名/新 IP 需暖機(逐日遞增發送量)
  3. HTML 郵件內聯 CSS,避免外部資源被拦截
  4. 提供 List-Unsubscribe Header,合規且減少投訴
  5. 監控發送成功率、退信率、打開率,異常報警

無論選擇 SMTP 直連還是 API,核心是可靠投遞、合規合法、可觀測。建議生產環境優先使用成熟的第三方郵件服務(SendGrid、Mailgun、騰訊雲郵件推送),專注業務邏輯而非郵件服務器運維。

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