1 簡介
在PHP中發送郵件,通常都是封裝一個php的smtp郵件類來發送郵件。但是PHP底層的socket編程相對於python來說效率是非常低的。CleverCode同時寫過用python寫的爬蟲抓取網頁,和用php寫的爬蟲抓取網頁。發現雖然用了php的curl抓取網頁,但是涉及到逾時,多線程同時抓取等等。不得不說python在網路編程的效率要比PHP好的多。
PHP在發送郵件時候,自己寫的smtp類,發送的效率和速度都比較低。特別是並發發送大量帶有附件報表的郵件的時候。php的效率很低。建議可以使用php調用python的方式來發送郵件。
2 程式
2.1 python程式
php的程式和python的檔案必須是相同的編碼。如都是gbk編號,或者同時utf-8編碼,否則容易出現亂碼。python發送郵件主要使用了email模組。這裡python檔案和php檔案都是gbk編碼,發送的郵件標題內容與本文內容也是gbk編碼。
#!/usr/bin/python# -*- coding:gbk -*- """ 郵件發送類"""# mail.py## Copyright (c) 2014 by http://blog.csdn.net/CleverCode## modification history:# --------------------# 2014/8/15, by CleverCode, Createimport threadingimport timeimport randomfrom email.MIMEText import MIMETextfrom email.MIMEMultipart import MIMEMultipartfrom email.MIMEBase import MIMEBasefrom email import Utils, Encodersimport mimetypesimport sysimport smtplibimport socketimport getoptimport osclass SendMail: def init(self,smtpServer,username,password): """ smtpServer:smtp伺服器, username:登入名稱, password:登入密碼 """ self.smtpServer = smtpServer self.username = username self.password = password def genMsgInfo(self,fromAddress,toAddress,subject,content,fileList,\ subtype = 'plain',charset = 'gb2312'): """ 組合訊息發送包 fromAddress:寄件者, toAddress:收件者, subject:標題, content:本文, fileList:附件, subtype:plain或者html charset:編碼 """ msg = MIMEMultipart() msg['From'] = fromAddress msg['To'] = toAddress msg['Date'] = Utils.formatdate(localtime=1) msg['Message-ID'] = Utils.make_msgid() #標題 if subject: msg['Subject'] = subject #內容 if content: body = MIMEText(content,subtype,charset) msg.attach(body) #附件 if fileList: listArr = fileList.split(',') for item in listArr: #檔案是否存在 if os.path.isfile(item) == False: continue att = MIMEText(open(item).read(), 'base64', 'gb2312') att["Content-Type"] = 'application/octet-stream' #這裡的filename郵件中顯示什麼名字 filename = os.path.basename(item) att["Content-Disposition"] = 'attachment; filename=' + filename msg.attach(att) return msg.as_string() def send(self,fromAddress,toAddress,subject = None,content = None,fileList = None,\ subtype = 'plain',charset = 'gb2312'): """ 郵件發送函數 fromAddress:寄件者, toAddress:收件者, subject:標題 content:本文 fileList:附件列表 subtype:plain或者html charset:編碼 """ try: server = smtplib.SMTP(self.smtpServer) #登入 try: server.login(self.username,self.password) except smtplib.SMTPException,e: return "ERROR:Authentication failed:",e #發送郵件 server.sendmail(fromAddress,toAddress.split(',') \ ,self.genMsgInfo(fromAddress,toAddress,subject,content,fileList,subtype,charset)) #退出 server.quit() except (socket.gaierror,socket.error,socket.herror,smtplib.SMTPException),e: return "ERROR:Your mail send failed!",e return 'OK'def usage(): """ 使用協助 """ print """Useage:%s [-h] -s <smtpServer> -u <username> -p <password> -f <fromAddress> -t <toAddress> [-S <subject> -c <content> -F <fileList>] Mandatory arguments to long options are mandatory for short options too. -s, --smtpServer= smpt.xxx.com. -u, --username= Login SMTP server username. -p, --password= Login SMTP server password. -f, --fromAddress= Sets the name of the "from" person (i.e., the envelope sender of the mail). -t, --toAddress= Addressee's address. -t "test@test.com,test1@test.com". -S, --subject= Mail subject. -c, --content= Mail message.-c "content, ......." -F, --fileList= Attachment file name. -h, --help Help documen. """ %sys.argv[0] def start(): """ """ try: options,args = getopt.getopt(sys.argv[1:],"hs:u:p:f:t:S:c:F:","--help --smtpServer= --username= --password= --fromAddress= --toAddress= --subject= --content= --fileList=",) except getopt.GetoptError: usage() sys.exit(2) return smtpServer = None username = None password = None fromAddress = None toAddress = None subject = None content = None fileList = None #擷取參數 for name,value in options: if name in ("-h","--help"): usage() return if name in ("-s","--smtpServer"): smtpServer = value if name in ("-u","--username"): username = value if name in ("-p","--password"): password = value if name in ("-f","--fromAddress"): fromAddress = value if name in ("-t","--toAddress"): toAddress = value if name in ("-S","--subject"): subject = value if name in ("-c","--content"): content = value if name in ("-F","--fileList"): fileList = value if smtpServer == None or username == None or password == None: print 'smtpServer or username or password can not be empty!' sys.exit(3) mail = SendMail(smtpServer,username,password) ret = mail.send(fromAddress,toAddress,subject,content,fileList) if ret != 'OK': print ret sys.exit(4) print 'OK' return 'OK' if name == 'main': start()
2.2 python程式使用協助
輸入以下命令,可以輸出這個程式的使用協助
# python mail.py --help
2.3 php程式
這個程式主要是php拼接命令字串,調用python程式。注意:用程式發送郵件,需要到郵件服務商,開通stmp服務功能。如qq就需要開通smtp功能後,才能用程式發送郵件。開通如。
php調用程式如下:
<?php/** * SendMail.php * * 發送郵件類 * * Copyright (c) 2015 by http://blog.csdn.net/CleverCode * * modification history: * -------------------- * 2015/5/18, by CleverCode, Create * */class SendMail{ /** * 發送郵件方法 * * @param string $fromAddress 寄件者,'clevercode@qq.com' 或者修改寄件者名 'CleverCode<clevercode@qq.com>' * @param string $toAddress 收件者,多個收件者逗號分隔,'test1@qq.com,test2@qq.com,test3@qq.com....', 或者 'test1<test1@qq.com>,test2<test2@qq.com>,....' * @param string $subject 標題 * @param string $content 本文 * @param string $fileList 附件,附件必須是絕對路徑,多個附件逗號分隔。'/data/test1.txt,/data/test2.tar.gz,...' * @return string 成功返回'OK',失敗返回錯誤資訊 */ public static function send($fromAddress, $toAddress, $subject = NULL, $content = NULL, $fileList = NULL){ if (strlen($fromAddress) < 1 || strlen($toAddress) < 1) { return '$fromAddress or $toAddress can not be empty!'; } // smtp伺服器 $smtpServer = 'smtp.qq.com'; // 登入使用者 $username = 'clevercode@qq.com'; // 登入密碼 $password = '123456'; // 拼接命令字串,實際是調用了/home/CleverCode/mail.py $cmd = "LANG=C && /usr/bin/python /home/CleverCode/mail.py"; $cmd .= " -s '$smtpServer'"; $cmd .= " -u '$username'"; $cmd .= " -p '$password'"; $cmd .= " -f '$fromAddress'"; $cmd .= " -t '$toAddress'"; if (isset($subject) && $subject != NULL) { $cmd .= " -S '$subject'"; } if (isset($content) && $content != NULL) { $cmd .= " -c '$content'"; } if (isset($fileList) && $fileList != NULL) { $cmd .= " -F '$fileList'"; } // 執行命令 exec($cmd, $out, $status); if ($status == 0) { return 'OK'; } else { return "Error,Send Mail,$fromAddress,$toAddress,$subject,$content,$fileList "; } return 'OK'; }}
2.3 使用範例
壓縮excel成附件,發送郵件。
<?php/** * test.php * * 壓縮excel成附件,發送郵件 * * Copyright (c) 2015 http://blog.csdn.net/CleverCode * * modification history: * -------------------- * 2015/5/14, by CleverCode, Create * */include_once ('SendMail.php');/* * 用戶端類 * 讓用戶端和商務邏輯儘可能的分離,降低頁面邏輯和商務邏輯演算法的耦合, * 使商務邏輯的演算法更具有可移植性 */class Client{ public function main(){ // 寄件者 $fromAddress = 'CleverCode<clevercode@qq.com>'; // 接收者 $toAddress = 'all@qq.com'; // 標題 $subject = '這裡是標題!'; // 本文 $content = "您好:\r\n"; $content .= " 這裡是本文\r\n "; // excel路徑 $filePath = dirname(FILE) . '/excel'; $sdate = date('Y-m-d'); $PreName = 'CleverCode_' . $sdate; // 檔案名稱 $fileName = $filePath . '/' . $PreName . '.xls'; // 壓縮excel檔案 $cmd = "cd $filePath && zip $PreName.zip $PreName.xls"; exec($cmd, $out, $status); $fileList = $filePath . '/' . $PreName . '.zip'; // 發送郵件(附件為壓縮後的檔案) $ret = SendMail::send($fromAddress, $toAddress, $subject, $content, $fileList); if ($ret != 'OK') { return $ret; } return 'OK'; }}/** * 程式入口 */function start(){ $client = new Client(); $client->main();}start();?>