本篇文章更新時間:2019/08/26
如有資訊過時或語誤之處,歡迎使用 Contact 功能通知。
一介資男的 LINE 社群開站囉!歡迎入群聊聊~
如果本站內容對你有幫助,歡迎使用 BFX Pay 加密貨幣 或 新台幣 贊助支持。
說實在這個主題還真的比較少討論,沒什麼資料可以參考,乾脆自己寫起來筆記。
使用 Gmail API 比傳統 Gmail SMTP 的做法麻煩,但好處是呼叫 API 的速度快且又不會犧牲安全性。
如果使用 Gmail SMTP 帳號密碼都打對的情況下還失敗,可以去檢查一下帳號是否有開啟「低安全性應用程式存取權」
WordPress 網站我也都是透過 Post SMTP 這款使用 Gmail API 串接。
那 PHP 要自己實作這功能怎辦? 我的心得是如果可以使用 AWS SES 或是 Mailgun 等專業發信服務就不要自己串了.... 哈哈哈
前置準備
安裝 Google Client 的 SDK 和 PHPMailer 的函式庫。
composer require google/apiclient:"^2.0"
composer require phpmailer/phpmailer
申請 Google API Console 開專案,啟用 Gmail API ,然後申請一個 OAuth 2.0 用戶端 ID。
申請好後會可以下載一個憑證檔案,包含 ID 和 密碼,記得改名檔案為: credentials.json
搭配 Google 提供的 Quickstart 範例,把程式與憑證檔案放在同一個目錄下後指令執行: php -f quickstart.php
期間會請你瀏覽一個連結,登入 Google 帳號、同意授權後取得 code
來之後換 Access Token
。
這邊我省略了滿多步驟的,像是 OAuth2.0 會需要指定授權的網域和一個回呼網址來接收那個 code
。
再來是範例中沒有開啟發信的服務,就是讀取信箱而已,所以要自己補上授權範圍(scope
)
$client->addScope("https://mail.google.com/");
上面的授權權限就是全開,自己要知道自己在幹啥囉~
把 code
貼回執行中的程式後就會取得授權碼(Access Token
),並存回同目錄下的檔案:token.json
到這個步驟,才算是準備好前期所需的資料:函式庫、指定授權的憑證檔案 credentials.json
和 token.json
。這兩個檔案我都建議要改檔名,免得被人猜到,或是直接寫進去程式,搭配資料庫來放,現在只是不要太麻煩的紀錄方法而已!
使用 PHPMailer 來協助發信前處理
要寫到這邊可真是碰雷碰到滿臉灰,這邊使用 PHPMailer 的原因不是來發信,而是協助轉換 Gmail API 需要吃的原始 MIME 格式,自己組裝基本上不是一件簡單的事,除非發出去的信就是純文字,不然都會碰到要自己組裝 MIME 格式的問題。
程式範例直接上最快:
$service = new Google_Service_Gmail($client);
try {
$mail = new PHPMailer();
$mail->CharSet = "UTF-8";
$mail->From = "發信端信箱";
$mail->FromName = "發信端別名";
$mail->AddAddress("收信端信箱", "收信端別名");
$mail->AddReplyTo("回信端信箱", "回信端別名");
$mail->Subject = "信件主題";
$mail->Body = "信件內文";
$mail->isHTML(true);
$mail->preSend();
$mime = $mail->getSentMIMEMessage();
$mime = rtrim(strtr(base64_encode($mime), '+/', '-_'), '=');
$mensaje = new Google_Service_Gmail_Message();
$mensaje->setRaw($mime);
$service->users_messages->send('me', $mensaje);
} catch (Exception $e) {
print($e->getMessage());
}
Gist: Link
如果有更好的方法產生出發信用的 MIME 也非常歡迎留言或來訊跟我分享XD
真正發信的呼叫就只有在這三行
$mensaje = new Google_Service_Gmail_Message();
$mensaje->setRaw($mime);
$service->users_messages->send('me', $mensaje);
其他部分自己都要想辦法組裝出那個 raw data ,生命有限,愛用函式庫~
後話
其實從頭到尾都可以使用 PHPMailer 這套函式庫來處理發信,它還提供取得授權碼的方法,支援 Google, Microsoft 和 Yahoo,就是也是要手工一點去改程式來配對。光是要拿到授權碼就可以難倒不少人了吧!
最後整理發信的那個方法如下:
function send_email($to_name = "", $to_email = "", $subject = "", $body = "", $reply_to = "") {
if ($to_name == "" || $to_email == "" || $subject == "" || $body == "") {
return false;
}
$client = new Google_Client();
$client->setAuthConfig('GoogleOAuth的網路應用程式用戶端資訊.json');
$tokenPath = '神秘的授權檔案.json';
if (file_exists($tokenPath)) {
$accessToken = json_decode(file_get_contents($tokenPath), true);
$client->setAccessToken($accessToken);
}
if ($client->isAccessTokenExpired()) {
// 判斷授權是否過期,過期就更新
if ($client->getRefreshToken()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
}
// 把更新過的授權碼資訊寫到檔案裡
if (!file_exists(dirname($tokenPath))) {
mkdir(dirname($tokenPath), 0700, true);
}
file_put_contents($tokenPath, json_encode($client->getAccessToken()));
}
if (file_exists($tokenPath)) {
$accessToken = json_decode(file_get_contents($tokenPath), true);
$client->setAccessToken($accessToken);
}
//使用 PHPMailer 準備原始信件內容
$mail = new PHPMailer();
$mail->CharSet = "UTF-8";
$mail->From = "發信端信箱";
$mail->FromName = "發信端名稱";
$mail->AddAddress($to_email, $to_name);
$mail->AddReplyTo($reply_to, "");
$mail->Subject = $subject;
$mail->Body = $body;
$mail->isHTML(true);
$mail->preSend();
$mime = $mail->getSentMIMEMessage();
// The message needs to be encoded in Base64URL
$mime = rtrim(strtr(base64_encode($mime), '+/', '-_'), '=');
try {
$msg = new Google_Service_Gmail_Message();
$msg->setRaw($mime);
$objGMail = new Google_Service_Gmail($client);
$objSentMsg = $objGMail->users_messages->send("me", $msg);
return empty($objSentMsg) ? false : true;
} catch (Exception $e) {
// print($e->getMessage());
return false;
}
}