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 程序源码下载