PHPMailer

出自福留子孫
在2018年2月21日 (三) 07:54由丁志仁對話 | 貢獻所做的修訂版本

跳轉到: 導覽搜尋

寄信

一、寄信類別

2017年版本:6.0.3版,適用於 PHP Version 5.5

寄信兩檔:

  1. PHPMailer.php
  2. SMTP.php

將它們置於同一個資料夾。

在 PHPMailer.php 的「protected function smtpSend($header, $body)」函式裡增加一行:

require_once 'SMTP.php';	// by jj

使其自動載入 SMTP.php 。

寄信的範例程式 smDemo.php:

<?php
require("./class/phpmailer/PHPMailer.php");
$mail = new PHPMailer\PHPMailer\PHPMailer;	// 依類別造物件
$mail->CharSet='utf-8';		// 設字集為utf-8,預設為iso-8859-1
$mail->IsSMTP();		// 設屬性 Mailer = 'smtp',指定由 SMTP 寄信
$mail->Host="smtp.gmail.com";	// SMTP servers 是那一台機器,預設值為 'localhost'
$mail->SMTPSecure='tls';	// GMail指定的認證方式,預設值為空字串
$mail->Port=587;		// GMail指定TLS認證的 port ,預設值為 25
$mail->SMTPAuth=true;		// 為打開 SMTP 認證,預設值為 false
$mail->Username='xxx@gmail.com';// SMTP 帳號,預設值為空字串
$mail->Password='********';	// SMTP 密碼,預設值為空字串
$mail->WordWrap=200;		// 多少字折行,預設值為 0,不折行
$mail->IsHTML(true);		// 設 ContentType='text/html',信是 HTML 格式
$mail->From='xxx@gmail.com';	// 寄件人郵址,預設值為 'root@localhost'
$mail->FromName='○○○';	// 寄件人姓名,預設值為 'Root User'
$mail->FromName='=?UTF-8?B?'.base64_encode($mail->FromName).'?=';
$mail->Subject='這是示範信件'; 	// 主旨,預設值為空字串
$mail->Subject='=?UTF-8?B?'.base64_encode($mail->Subject).'?=';
// 信文從此開始,屬性Body,預設值為空字串
$images=array();
$fn='../路徑/示範信.html';
$bodyDirname=dirname($fn);
if(filesize($fn)>0){		// 信文檔不是空檔
	$f=fopen($fn,"r");
	$body=fread($f,filesize($fn));
	fclose($f);
	$mail->Body=str_replace("src='./images/","src='cid:",$body);	// 將 src 換成 cid,並移除路徑
	$temp=cuts("src='","'",$body);					// 將所有src指示的圖檔,取成陣列
	foreach($temp as $k=>$v){$images[$v]=1;}			// 利用索引的唯一性,消除重覆的圖檔
	$images=array_keys($images);					// 索引才是我們想要的諸檔
}else{$mail->Body='';}
// 信文到此結束
/// 加信的圖
foreach($images as $image){
	if($image){
		$mail->AddEmbeddedImage($bodyDirname.'/'.$image,basename($image),basename($image),"base64","image/".substr(basename($image),-1*(strlen(strstr(basename($image),'.'))-1)));
	}
}
$mail->ClearAllRecipients();	// 清空收件者陣列
$mail->AddAddress('yyy@gmail.com','=?UTF-8?B?'.base64_encode('☆☆☆').'?=');	// 加入收件者
$mail->Send();
// 以 $start開始、$end結束所夾的字串,蒐集起來構成陣列
function cuts($start,$end,$str,$se=null){
	$len1=strlen($start);
	$len2=strlen($end);
	$ret=array();
	while(strlen($str)>0){
		$str=strstr($str,$start);
		$str=substr($str,$len1);
		if(strlen(substr($str,0,strpos($str,$end)))>0){
			if($se==1){$ret[]=$start.substr($str,0,strpos($str,$end));}
			elseif($se==2){$ret[]=substr($str,0,strpos($str,$end)).$end;}
			elseif($se==3){$ret[]=$start.substr($str,0,strpos($str,$end)).$end;}
			else{$ret[]=substr($str,0,strpos($str,$end));}
		}
		$str=strstr($str,$end);
		$str=substr($str,$len2);
	}
	return $ret;
}
?>

二、寄信布署

當要寄數千封信時,不要用一支 php 程式從頭寄到底,中途會逾時。比較好的做法如下:

  • 在 /etc/crontab 中加一行,每十鐘觸動一次排程:
#minute	hour	mday	month	wday	who	command
*/5	*	*	*	*	root	/usr/bin/php /volume1/web/smsEDM.php
  • 相應修改 php 的最長執行時間:
    1. 因為DS216+在 /volume1/@appstore/Apache2.2/usr/local/etc/apache22/conf/extra/httpd-default.conf 設定「Timeout 300」除非修改它,否則最多只能五分鐘觸動一次。
    2. 修改「DSM/Web Station/PHP 設定/編輯配置檔/核心設定/搜尋max_execution_time/預設為 240 改為 300/確定」
    3. 相應修改 default.php 中的 $limit 變數,改為 65 。
  • 在文件根目錄中,造 smsEDM.php ,供排程觸動,簡單版如下:
#!/usr/bin/php
<?php
$socket=socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
socket_connect($socket,'localhost',80);
$command="GET /路徑/smsEDM.php?act=約定 HTTP/1.0\nhost:localhost\n\n";
socket_write($socket,$command,strlen($command));
socket_close($socket);
?>
  • 在指定路徑下建立寄信程式,如果由通道送入約定,就開始寄信。
  • 寄信休息期間將 smsEDM.php 改名為 smsEDM-.php ,即可停止發信。

三、gmail 的寄信限制

  • google 每日寄信數量限制的說明(英文)中說每天限寄 500 封信,實測結果在2018年初寄信上限大約在每天 1000 封上下,過量會無法寄信,但過當地時間午夜12點,會恢復寄信功能。
  • 該信建議使用通訊群組做相同的事,但我們並沒辦法做到通信群組中人人都認同,所以並不可行。

四、寄信資料表的整理要領

  1. 用「select * from 表名 where 姓名欄 regexp '\\w+'」來找出機器人報名、註冊的人,其姓名欄會只有英,數字元。
  2. 將含有「@googlegroups.com」排在前面。

五、寄完信的善後

收信

IMAP 和 POP 是存取電子郵件的兩種方法。如果需要在多個不同裝置(例如手機、膝上型電腦、平板電腦)上檢查電子郵件,就建議使用 IMAP​​。

使用 IMAP 存取或讀取電子郵件時,並非實際將郵件下載或儲存於 client 端的電腦,而是從電子郵件服務中讀取。比起 POP,可以快速的檢查郵件。

POP 的運作方式是與郵件伺服器連線,並下載郵件伺服器中的所有新郵件。一旦郵件下載至 client 端後,郵件伺服器就會將它們刪除。這表示電子郵件下載之後,就只能使用同一台電腦來存取該郵件。

POP3.php中的方法

公開的方法

  1. popBeforeSmtp:用authorise登入POP並回傳結果。在寄信之前先以 POP3 收信,由於收信的認證資料會有短時間存在主機裡面,因此在 POP 收信完成後,就可以寄信,這個時候的寄信認證的機制就是使用前一時間的 POP 的認證。
  2. authorise:連接POP並login。
  3. connect:用fsockopen去連接POP。
  4. login:用sendString方法(即fwrite)去登入POP。
  5. disconnect:用fclose去結束POP連線。
  6. getErrors:return $this->errors;。

私用的方法

  1. getResponse($size=128):用fgets由POP連線取回應,一方面echo 回應,一方面return 回應。
  2. sendString($string):用fwrite將$string寫入pop連線並回傳結果,同時echo $string。
  3. checkResponse($string):檢查$string前三byte是否為'+OK',是就回傳真,否就回傳假,並將$string塞入屬性errors陣列,成為其一個元素。
  4. setError($error):將$error字串塞入屬性errors陣列,並依屬性do_debug的值,決定是否印出。
  5. catchWarning($errno,$errstr,$errfile,$errline):串接$errno,$errstr,$errfile,$errline成長字串,塞給setError方法。

原始指令

  1. 用 fsockopen(POP3 Host,Port,Error Number,Error Message,Timeout seconds)去得到連結。
  2. 用 fwrite(連結,命令,命令長度) 下命令:
    • USER 帳號換行:提供帳號。
    • PASS 密碼換行:提供密碼。
    • QUIT:結束。
  3. 用 fclose(連結):繳還連結。

POP3指令清單

信件編號為n

  1. TELNET mail.company.com.tw 110
  2. USER:命令輸入用戶信箱名。例:USER sendname
  3. PASS:輸入用戶信箱密碼。例:PASS sendpassword
  4. STAT:伺服器將告訴用戶共有多少封信件在信箱中。
  5. LIST:顯示信件個數、序號和每個信件的大小。
  6. TOP n m:顯示第n個信件前m行的內容。
  7. RETR n:顯示第n個信件的全部內容。
  8. DELE n:刪除指定的第n個信件。
  9. RSET:將所有標示為『刪除』的信件, 全部還原成尚未標示成刪除的狀態。(Reset,重設)
  10. LAST:顯示下一個信件的編號。
  11. UIDL [n]:將指定信件的識別碼列出來。沒有 n 則全列。(Unique-ID Listing,識別碼列示)
  12. NOOP:不執行任何操作,僅用來測試伺服器的回應是否正常。
  13. QUIT:退出 Server,結束信件查閱過程,POP3伺服器進入更新階段。郵件伺服器會刪除掉『已標示刪除』的信件, 傳回『再見』訊息, 結束『更新』階段。

POP3.php中的屬性

Array
(
    [do_debug] => 0
    [host] => 
    [port] => 
    [tval] => 
    [username] => 
    [password] => 
)

PHP 有 IMAP 的專屬函式

連接範例如下:

<?php
$res=@imap_open("{localhost/imap/ssl}","帳號","密碼",NULL,1);
imap_errors();imap_alerts();	// 消滅錯誤訊息
if($res===false){echo "login failed";}
else{imap_close($res);echo "login successed";}
?>

運用這些函式做成類別 receivemail.class.php ,其使用範例是 example.php 。

參考資料

  1. POP3指令
  2. SMTP及POP3指令
  3. 設定Gmail信箱使用POP3協定收其他非gmail帳號的信
  4. 使用其他電子郵件程式讀取 Gmail 郵件(透過POP協定)
  5. google 蒐「gmail 使用 POP3」能得到更多有用的說明。
  6. 參考資料列表
  7. PHP接收邮件类receivemail.class.php
  8. 用PHP写的POP3电子邮件收取流程