## 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, Create
import threading
import time
import random
from email.MIMEText import MIMEText
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email import Utils, Encoders
import mimetypes
import sys
import smtplib
import socket
import getopt
import os
class 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();
?>
~~~
### 2.4 程序源碼下載
[http://download.csdn.net/detail/clevercode/8711809](http://download.csdn.net/detail/clevercode/8711809)
**版權聲明:**
1)原創作品,出自"CleverCode的博客",轉載時請務必注明以下原創地址,否則追究版權法律責任。
2)原創地址:[http://blog.csdn.net/clevercode/article/details/45815453](http://blog.csdn.net/clevercode/article/details/45815453)(轉載務必注明該地址)。
3)歡迎大家關注我博客更多的精彩內容:[http://blog.csdn.net/CleverCode](http://blog.csdn.net/CleverCode)。