python发送邮件

电子邮件与协议

发送计算机需要找到某一台中间主机,接着这台中间主机需要找到离接受主机更近的一些主机,所以在发送主机和接受主机之间会有多台被称为跳板的主机。每一个电子邮件消息头标题,就会记录它在被接受之前经过了哪里。
消息传输代理(MTA)
这是在邮件交换主机上运行的服务器进程,它负责邮件的路由、队列处理和发送工作。MTA就是发送端与最终接受端之间的跳板主机,也称为消息传输的代理。
MTA负责两件事:
——如何找到消息应该到达的下一台MTA(由DNS来查找目的域名的MX来完成)
——如何与另一台MTA进行通信;
MTA之间的通信协议
为了发送电子邮件,邮件客户端必须连接到一个MTA,MTA之间通过消息传输系统互相通信,只有两个MTA都是用这个协议时才能进行通信。

  • SMTP
    SMTP时两个MTA主机之间通信的一种协议,它需要一个邮件队列,但这需要额外的存储和管理工作。用SMTP把一个邮件消息从一台MTA发送给另一台MTA,发送时必须连接到一个外部STMP服务器,此时邮件程序是一个SMTP客户端,而SMTP服务器也称为消息的第一站。

  • LMTP
    LMTP提供了更轻量级的系统,以除了对邮件队列的需求,但邮件需要立即发送,LMTP服务器不暴露到外面直接与连接到因特网的邮件网关工作,以表示接受或拒绝一个消息,网关作为LMTP的邮件队列。

  • POP(邮局协议)
    第一个用于下载邮件的协议,目的是让用户在工作站可以访问邮箱服务器里的邮件

  • IMAP
    比POP拥有更完整的解决方案,POP无法很好地应对多邮件客户端,而IMAP则可以通过不同的设备使用电子邮件。

邮件发送

基本流程:

  • 连接到服务器
  • 登录
  • 发出服务请求
  • 退出

1.用163和qq邮箱来实现
登陆163邮箱网页版,在设置里开启POP3/SMTP/IMAP服务,用手机短信认证设置授权码
python发送邮件_第1张图片
2.python实现

  • 发送一个普通文本内容
    将设置信息放在配置文件
    mailConf.py
smtpServer='smtp.163.com'  #使用的服务器
sender='[email protected]'	#发送端的邮箱地址
passwd='we***23'	#授权码
receiver='148***[email protected]' #接受端的邮箱地址
subject='python20180304' #发送的主题
 #发送的内容
content="""  
    hello python
"""
import smtplib
from email.mime.text import MIMEText   #生成内容正确格式的模块
from mailConf import *  #配置文件

def mail_content():   #生成发送内容的函数
    msg=MIMEText(content,'plain','utf-8') 
    msg['From']=sender
    msg['To']=receiver
    msg['Subject']=subject

    return msg

def sendMail():
    try:
        smtpObj=smtplib.SMTP(smtpServer)  #生成一个对象,传入使用的服务器
        smtpObj.login(sender,passwd) #登陆邮箱,邮箱地址和授权码
        msg=mail_content()    #发送内容的对象
        smtpObj.sendmail(sender,receiver,msg.as_string())
    except smtplib.SMTPException as e:
        print("Error:send email failure:",e)
    else:
        print("send email success")


if __name__=='__main__':
    sendMail()


  • 发送一个HTML格式的文件
    配置文件
    mainConf.py
smtpServer='smtp.163.com'
sender='[email protected]'
passwd='westos123'
receiver='[email protected]'
subject='hello_HTML'

with open('main_html.html') as f:
    content=f.read()

import smtplib
from email.mime.text import MIMEText

from mailConf import *

def mail_content():
    # 是一个MIMETEXT对象, 如果发送的是普通的文本文件, 则添加
    msg = MIMEText(content, 'html', 'utf-8')
    msg['From'] = sender
    # 如果要给多个用户发送邮件, 需要将列表连接成字符串;
    msg['To'] = "".join(receiver)
    msg['Subject'] = subject
    return  msg

def sendMail():
    try:
        # 1. 连接smtp服务器;
        smtpObj = smtplib.SMTP(smtpServer)
        # 2. 登陆账户
        smtpObj.login(sender, passwd)
        # 生成合法格式的内容, 否则发送失败;
        msg = mail_content()
        # 3. 发送邮件
        smtpObj.sendmail(sender, receiver, msg.as_string())
    except smtplib.SMTPException as e:
        print("Error:邮件发送失败,",e)
    else:
        print("邮件发送%s成功" %(receiver))

if __name__ == "__main__":
    sendMail()
  • 发送带附件的电子邮件
    发送带附件的邮件,首先要创建MIMEMultipart()实例,然后构造附件,如果有多个附件,可依次构造,最后利用smtplib.smtp发送。
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from mailConf import *


def read_file(filename):
    """读取附件文件的内容"""
    with open(filename, 'rb') as f:
        c_str = f.read()
    return c_str


def mail_content():
    # 创佳一个 MIMEMultipart对象, 可以添加很多内容, 比如附件
    # **************此处修改MIMEMultipart()实例可以添加附件**************
    msg = MIMEMultipart()

    msg['From'] = sender
    # 如果要给多个用户发送邮件, 需要将列表连接成字符串;
    msg['To'] = "".join(receiver)
    msg['Subject'] = subject


    # 添加邮件正文
    msg.attach(MIMEText("这是一个有附件的邮件正文."))

    # 构造邮件的附件
    att1_content = read_file('/etc/passwd')
    # 构建附件1:
    # Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,
    # Base64就是一种基于64个可打印字符来表示二进制数据的方法。
    att1 = MIMEText(att1_content, 'base64', 'utf-8')

    # Content-Type,内容类型,一般是指网页中存在的Content-Type,
    # 用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件,
    # 这就是经常看到一些Asp网页点击的结果却是下载到的一个文件或一张图片的原因。
    # 'application/octet-stream': .* ( 二进制流,不知道下载文件类型)
    att1['Content-type'] = 'application/octet-stream'

    # HTTP应答中,Content-Disposition 消息头指示回复的内容该以何种形式展示,
    # 是以内联的形式(即网页或者页面的一部分),还是以附件的形式下载并保存到本地
    #
    # inline(默认值,表示回复中的消息体会以页面的一部分或者整个页面的形式展示),
    # attachment(意味着消息体应该被下载到本地;大多数浏览器会呈现一个“保存为”的对话框,
    #   将filename的值预填为下载后的文件



    msg.attach(att1)
    return msg


def sendMail():
    try:
        # 1. 连接smtp服务器;
        smtpObj = smtplib.SMTP(smtpServer)
        # 2. 登陆账户
        smtpObj.login(sender, passwd)
        # 生成合法格式的内容, 否则发送失败;
        msg = mail_content()
        # 3. 发送邮件
        smtpObj.sendmail(sender, receiver, msg.as_string())
    except smtplib.SMTPException as e:
        print("Error:邮件发送失败,", e)
    else:
        print("邮件发送%s成功" % (receiver))


if __name__ == "__main__":
    sendMail()

  • 发送带图片的HTML邮件


import smtplib
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from mailConf import *


def read_file(filename):
    """读取附件文件的内容"""
    with open(filename, 'rb') as f:
        c_str = f.read()
    return c_str

def mail_content():
    # 创佳一个 MIMEMultipart对象, 可以添加很多内容, 比如附件
    # **************此处修改MIMEMultipart()实例可以添加附件**************
    # multipart/related类型除了可以携带各种附件外,
    # 还可以将其它内容以内嵌资源的方式存储在邮件中。
    # 比如我们在发送html格式的邮件内容时,可能使用图像作为html的背景;
    msg = MIMEMultipart()

    msg['From'] = sender
    # 如果要给多个用户发送邮件, 需要将列表连接成字符串;
    msg['To'] = "".join(receiver)
    msg['Subject'] = subject

    # multipart / alternative类型
    # 如果邮件中同时存在纯文本和超文本内容,则邮件需要在Content - Type
    # 域中定义multipart / alternative类型,
    # 邮件通过其boundary中的分段标识将纯文本、超文本和邮件的其它内容分成不同的段。
    msgAlter = MIMEMultipart()
    msg.attach( msgAlter)

    mail_msg = """
    

hello

上海鲜花港 - 郁金香 #如果图片不能显示就显示"上海鲜花港 - 郁金香" """ msgAlter.attach(MIMEText(mail_msg, 'html', 'utf-8')) with open('img/img01.jpg', 'rb') as f: msg_image = MIMEImage(f.read()) msg_image.add_header('Content-ID','' ) msgAlter.attach(msg_image) return msg def sendMail(): try: # 1. 连接smtp服务器; smtpObj = smtplib.SMTP(smtpServer) # 2. 登陆账户 smtpObj.login(sender, passwd) # 生成合法格式的内容, 否则发送失败; msg = mail_content() # 3. 发送邮件 smtpObj.sendmail(sender, sender, msg.as_string()) except smtplib.SMTPException as e: print("Error:邮件发送失败,", e) else: print("邮件发送%s成功" % (receiver)) if __name__ == "__main__": sendMail()

自动提醒带伞案例

设计思路:在系统中设置定时任务执行脚本,每天早上8:00从天气网中得到需要的天气数据,在经过处理,如果是雨天或雪天就自动发送电子邮件提醒带伞。

def readUrl(url):
    # 生成字典, 指定用户代理为火狐浏览器, 而不是python脚本;
    headers = {'User-Agent': 'Firefox/23.0'}
    # 向url地址发起请求, 返回一个Request对象;
    req = request.Request(url, headers=headers)
    # 返回一个urlOpen对象, 该对象中包含访问的所有结果, 比如: 网页内容, 网页的状态码(200, 404)
    urlObj = urlopen(req)
    # 将读取的内容以utf-8编码显示;(中文显示不乱码)
    urlContent = urlObj.read().decode('utf-8')
    return  urlContent


def sendMail():
    try:
        # 1. 连接smtp服务器;
        smtpObj = smtplib.SMTP(smtpServer)
        # 2. 登陆账户
        smtpObj.login(sender, passwd)
        # 生成合法格式的内容, 否则发送失败;
        msg = mail_content()
        # 3. 发送邮件
        smtpObj.sendmail(sender, receiver, msg.as_string())
    except smtplib.SMTPException as e:
        print("Error:邮件发送失败,",e)
    else:
        print("邮件发送%s成功" %(receiver))
    

def main():
    url = "http://www.weather.com.cn/data/cityinfo/101110101.html"
    info = readUrl(url)
    d = json.loads(info)
    weather = d['weatherinfo']['weather']

    if '雨' in weather or '雪' in weather:
        sendMail()
if __name__=="__main__":
main()

在系统中设置定时任务
[kiosk@foundation77 Desktop]$ vim /etc/cron.d/filename
python发送邮件_第2张图片

你可能感兴趣的:(Python语言)