Python之smtplib发送邮件 by二卷

时间:2022-01-01 18:09:29


SMTP 基础知识

1.SMTP 的会话方式

1.邮件直接投递
发送邮件给XXX@163.com,直接链接163.com的邮件服务器,把邮件给XXX@163.com


2.验证过后发信
你有YYY@126.com邮箱发送邮件给XXX@163.com,要先连接126.com的smtp服务器,然后认证,之后在把要发到163.com的信件投到126.com上,126.com会帮你把信投递到163.com。


email使用语法

1.创建简单的纯文本文件

from email.mime.text import MIMEText
msg = MIMEText('hello world!', 'plain', 'utf-8') #返回MIMEText对象
#'hello world!'为邮件正文;'plain'是MIME的子类型;
#一定要用utf-8编码保证多语言兼容性

注:MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型。是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。例:text/plain 就是一个MIME类型,text是类型 & plain是子类型,文件设置为纯文本的形式,浏览器在获取到这种文件时并不会对其进行处理。


smtplib使用语法

1.创建python的SMTP对象

import smtplib

smtpObj = smtplib.SMTP( [host [, port [,local_hostname]]] )
#host: SMTP 服务器主机,可以指定主机的ip地址或者域名(可选)
#port: 有host 参数则要指定SMTP服务使用的端口号,一般为25
#local_hostname:SMTP在本机上,只需指定服务器地址为 localhost

2.python的SMTP对象使用sendmail方法发送邮件

smtpObj.sendmail(from_addr, to_addrs, msg[, mail_options, rcpt_options])
#from_addr: 邮件发送者地址
#to_addrs: 字符串列表,邮件发送地址
#msg: 发送消息,字符串,格式是smtp协议中定义的格式


实例

1.primer(发送纯文本)

#!/usr/bin/python
# -*- encoding:utf-8 -*-

from email.mime.text import MIMEText
import smtplib
from email.header import Header
from email.utils import parseaddr, formataddr

'''
这里采用的是间接方式,就是上述的验证后发信。如果你有一个163.com的邮箱,
想发送给一个126.com的邮箱,先链接163.com的邮箱服务器,登录你的邮箱后,
再通过1163.com的邮箱服务器发送邮件给126.com的邮箱。
注:通过第三方的邮件服务器发送邮件比较通用,你自己的服务器发邮件很容易被接收方判定为垃圾邮件
'''
def _format_addr(s): #定义一个不能被其他文件import的函数,主要用于处理邮件的编码问题
name, addr = parseaddr(s) #如果是erjuan<erjuan.163.com>,则name就是erjuan, addr就是erjuan.163.com,注意邮箱格式要对
#变成准确的邮件需要的编码
return formataddr(( \
Header(name, 'utf-8').encode(), \
addr.encode('utf-8') if isinstance(addr, unicode) else addr))

from_addr = raw_input('From: ') #输入你需要登录认证邮箱的地址,就是你自己的邮箱
password = raw_input('Password: ') #你邮箱的密码
smtp_server = raw_input('SMTP server: ')# 输入SMTP服务器地址,如果你用是163邮箱,那么就是:smtp.163.com
to_addr = raw_input('To: ')# 输入收件人地址

emailContent = MIMEText('hello world!', 'plain', 'utf-8')
#关于Header见官网https://docs.python.org/2/library/email.header.html?highlight=email.head#module-email.header
emailContent['From'] = _format_addr(u'二卷<'+from_addr+'>')
emailContent['To'] = _format_addr(u'You<'+to_addr+'>')
#emailContent['From'] = Header("二卷<erjuan@163.com>", 'utf-8')
#emailContent['To'] = Header("You<xxxx@126.com", 'utf-8')#直接这样使用,会出现乱码问题
emailContent['Subject'] = Header('来自二卷的邮件哦', 'utf-8').encode()

server = smtplib.SMTP(smtp_server, 25)# 连接邮件服务器,SMTP协议默认端口是25
#server = smtplib.SMTP('localhost') 使用这个话的时候一般需要你的机器上安装有发送邮件的程序,例如sendmail
#server.set_debuglevel(1)#打印流程
server.login(from_addr, password)#登录你的邮箱
server.sendmail(from_addr, [to_addr], emailContent.as_string())#发送邮件
server.quit()

结果展示
Python之smtplib发送邮件 by二卷

Bug
如果出现smtplib.SMTPDataError: (554, …… 这样的报错是因为你的真实的邮件地址和你在From和to中填写的不一致

2.primer+1(发送html)

只需要修改primer中发送文本的emailContent = MIMEText(……)这个语句,把plain换成html,然后第一个参数写上html的语句

emailContent = MIMEText('<html><body><h1>Hello world!</h1>' +
'<a href="http://www.baidu.com">百度</a>' +
'</body></html>', 'html', 'utf-8')

结果展示
Python之smtplib发送邮件 by二卷

3.advance(发送附件)

发送带附件的方法蛮多的,这里介绍一个简单的,需要创建MIMEMultipart()实例,比较简单的是使用都用MIMEApplication来添加附件,MIMEApplication默认子类型是application/octet-stream(表示二进制文件,根据其后缀进行处理)

#!/usr/bin/python
# -*- encoding:utf-8 -*-

from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
import smtplib
from email.header import Header
from email.utils import parseaddr, formataddr


def _format_addr(s):
name, addr = parseaddr(s)
return formataddr(( \
Header(name, 'utf-8').encode(), \
addr.encode('utf-8') if isinstance(addr, unicode) else addr))

from_addr = raw_input('From: ')
password = raw_input('Password: ')
smtp_server = raw_input('SMTP server: ')
to_addr = raw_input('To: ')

#创建一个带附件的实例
emailContent = MIMEMultipart()
emailContent['From'] = _format_addr(u'二卷<'+from_addr+'>')
emailContent['To'] = _format_addr(u'You<'+to_addr+'>')
emailContent['Subject'] = Header('来自二卷的邮件哦', 'utf-8').encode()

#邮件中的文本信息
emailText = MIMEText("This email has attachment", 'plain', 'utf-8')
emailContent.attach(emailText)

#邮件中的附件信息,一般来说会判断一下附件的文件类型,我们这里是图片,就不判断了
img = open('picture.png', 'rb')
attachment = MIMEImage(img.read())
img.close()
emailContent.attach(attachment)

server = smtplib.SMTP(smtp_server, 25)
server.login(from_addr, password)
server.sendmail(from_addr, [to_addr], emailContent.as_string())
server.quit()

结果展示

Python之smtplib发送邮件 by二卷

3.advance+1(在正文中显示图片)

正文中的图片用html语言来引用附件中的,只需要把上面的代码稍作修改
这个方法的话附件还是存在的

#!/usr/bin/python
# -*- encoding:utf-8 -*-

from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
import smtplib
from email.header import Header
from email.utils import parseaddr, formataddr


def _format_addr(s):
name, addr = parseaddr(s)
return formataddr(( \
Header(name, 'utf-8').encode(), \
addr.encode('utf-8') if isinstance(addr, unicode) else addr))

from_addr = raw_input('From: ')
password = raw_input('Password: ')
smtp_server = raw_input('SMTP server: ')
to_addr = raw_input('To: ')

#创建一个带附件的实例
emailContent = MIMEMultipart()
emailContent['From'] = _format_addr(u'二卷<'+from_addr+'>')
emailContent['To'] = _format_addr(u'You<'+to_addr+'>')
emailContent['Subject'] = Header('来自二卷的邮件哦', 'utf-8').encode()

#邮件中的文本信息
emailText = MIMEText('<html><body><h1>Hello world!</h1>' +
'<p>邮件文本中有图片</p><p><img src="cid:pp"></p>' +
'</body></html>', 'html', 'utf-8')
emailContent.attach(emailText)

#邮件中的附件信息,一般来说会判断一下附件的文件类型,我们这里是图片,就不判断了
img = open('picture.png', 'rb')
attachment = MIMEImage(img.read())
#给你的附件命名,这里叫pp,这样在上面的html中好引用,用cid
attachment.add_header('Content-ID', 'pp')
img.close()
emailContent.attach(attachment)

server = smtplib.SMTP(smtp_server, 25)
server.login(from_addr, password)
server.sendmail(from_addr, [to_addr], emailContent.as_string())
server.quit()

结果展示
Python之smtplib发送邮件 by二卷