PHPMailer

出自福留子孫
在2018年2月20日 (二) 19:06由丁志仁對話 | 貢獻所做的修訂版本

跳轉到: 導覽搜尋

寄信

寄信類別

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);
?>
  • 在指定路徑下建立寄信程式,如果由通道送入約定,就開始寄信。

gmail 的寄信限制

  • google 每日寄信數量限制的說明(英文)中說每天限寄 500 封信,其實大約在 1000 封上下。
  • 該信建議使用通訊群組做相同的事,但我們並沒辦法做到通信群組中人人都認同,所以並不可行。

收信

方法

公開的方法

  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指令清單

  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. LAST:顯示下一個信件的編號。
  10. NOOP:不執行任何操作,僅用來測試伺服器的回應是否正常。
  11. QUIT:退出 Server,結束信件查閱過程。

屬性

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

參考資料

  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电子邮件收取流程