python 学习笔记 Email

来源:互联网 发布:化妆品成分知多少 编辑:程序博客网 时间:2024/05/02 04:16
十七:电子邮件
                    一封电子邮件的旅程就是:发件人-->MUA-->MTA-->MTA-->若干个MTA-->MDA<--MUA<--收件人  
                    MTA:Mail Transfer Agent 邮件传输代理  MUA:Mail User Agent 邮件用户代理  MDA:Mail Delivery Agent 邮件投递代理
                    要编写程序来发送和接受邮件 本质上是:
                        1:编写MUA把邮件发送到MTA
                        2:编写MUA从MDA上收邮件
                    
                    1:SMTP发送邮件
                        SMTP是发送邮件的协议 Python内置对SMTP的支持 可以发送纯文本邮件 HTML文件以及带附件的邮件
                        Python对SMTP支持有smtplib 和email 两个模块 email负责构造邮件 smtplib 负责发送邮件
                        首先 我们来构造一个最简单的纯文本邮件:
                            from email.mime.text import MIMEText
                            msg=-MIMEText('Hello ,send by Python...','plain','utf-8')
                         注意到构造MIMEText对象时,第一个参数是邮件正文,第二个参数是MIME的subtype传入‘plain’最终的MIME就是‘text/plain’最后一定要用'urf-8'
                        然后通过SMTP发送出去
                            #输入Email的地址和口令
                            from_addr=raw_input('From:')
                            password=raw_input('Password:')
                            #输入SMTP服务器的地址
                            smtp_server=raw_input('SMTP server:')
                            #输入收件人地址
                            to_addr=raw_input('To:.....')
                
                            import smtplib
                            server=smtplib.SMTP(smtp_server,25)
                            server.set_debuglevel(1)
                            server.login(from_addr,password)
                            server.sendmail(from_addr,[to_addr],msg.as_tostring())
                            server.quit()

                        我们用set_debuglevel(1)就可以打印出和SMTP服务器交互的所有信息 SMTP协议就是简单的文本命令和响应 login()方法用来登录SMTP服务器 sendmail()方法就是发邮件由于一次可以给多个人发 所以传入 的是一个list 邮件正文是一个str  as_tostring 把MIMETest 对象转化为一个str
                        如果一切顺利 就可以在收件人信箱里面收到我们刚发送的信息      
                        但是邮件1:没有主题 2:邮件人的名字没有显示为友好的名字 3:明明收到了邮件 却提示不在收件人中
                        我们需要把 from  to subject 添加到MIMETest中
                    
                            #-*-coding:utf-8-*-
                    
                            from email import encoders
                            from email.header import Header
                            from email.mime.text import MIMEText
                            from emial.utils import parseaddr,formataddr
                            import smtplib

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

                            from_addr=raw_input('From')
                            password=raw_input('Password: ')
                            to_addr=raw_input('To:')
                            smtp_server=raw_input('smtp server:')
                            
                            msg=MIMEText('hello ,send by Python ....','plain','utf-8')
                            msg['From']=_format_addr(u'Python 爱好者 <%s>' % from_addr)
                            msg['To'] = _format_addr(u'管理员 <%s>' % to_addr)
                            msg['Subject'] =Header(u'来自SMTP的问候','utf-8').encoding()
                
                            server=smtplib.SMTP(smtp_server,25)
                            server.set_debuglevel(1)
                            server.login(from_addr,password)
                            server.sendmail(from_addr,[to_addr],msg.as_tostring())
                            server.quit()

                    发送HTML邮件
                        如果要发送HTML邮件 而不是普通的纯文本文件 方法就是 在构造MIMEText对象时 把HTML字符串传进去 再把第二个参数由plain 变为 html 就可以了
                        msg=MIMEText('<html><body><h1>Hello</h1>'+'<p>send by <a href="http://www.baidu.com">Pytohn</a>...</p>'+'</body></html>','html','utf-8')  

                    发送附件: 如果要发送附件 可以构造一个MIMEMultipart 对象代表邮件本身 然后往里面加上一个MIMEText 作为邮件正文 在继续往里面加上表示附件的MIMEBase对象即可
                
                            #邮件对象
                            msg=MIMEMultipart()
                            msg['From']=_format_addr(u'Python 爱好者 <%s>' % from_addr)
                            msg['To'] = _format_addr(u'管理员 <%s>' % to_addr)
                            msg['Subject'] =Header(u'来自SMTP的问候','utf-8').encoding()
            
                            #邮件正文是MIMEText:
                            msg.attach(MIMEText('hello ,send by Python ....','plain','utf-8'))

                            #添加附件就是加上一个MIMEBase 从本地读取一个图片
                            with open('a.png','rb') as f:
                                #设置附件的MIME和文件名 这里是png类型:
                                mime=MIMEBase('image','png',filename='a.png')
                                #加上必要的头信息
                                mime.add_header('Content-Disposition','attachment',filename='a.png')
                                mime.add_header('Content-ID','<0>')
                                mime.add_header('X-Attachment-Id','0')
                                #把附件类容读进来
                                mime.set_payload(f.read())
                                #利用base64编码
                                encoders.encode_base64(mime)
                                #添加到MIMEMultipart:
                                msg.attach(mime)

                            server=smtplib.SMTP(smtp_server,25)
                            server.set_debuglevel(1)
                            server.login(from_addr,password)
                            server.sendmail(from_addr,[to_addr],msg.as_tostring())
                            server.quit()

                    发送图片:
                        如果要把一个图片嵌入到正文中怎么做  ?要把图片嵌入到正文中 我们只需要按照发送邮件的方式 先把邮件作为附件添加进去 然后在HTML中通过引用 src='cid=:0' 就可以把有附件作为图片嵌入了
                            msg.attach(MIMEText('<html><body><h1>Hello</h1><p><img src="cid:0"/></p></body></html>','html','utf-8'))

                    同时支持HTML和plain格式
                        如果收件人使用的设备太老看不了HTML邮件 将其自动降级为纯文本文件
                        利用MIMEMultipart 就可以组合一个HTML和plain 要注意subtype是alternative
                            msg=MIMEMultipart('alternative')
                            msg['From']=......
                            msg['To']=.....
                            msg['Subject']=.....
            
                            msg.attach(MIMEText('Hello','plain','utf-8'))
                            msg.attach(MIMEText('<html><body><h1>Hello</h1>'+'<p>send by <a href="http://www.baidu.com">Pytohn</a>...</p>'+'</body></html>','html','utf-8')  )
                            ........
        
                    加密SMTP
                        smtp_server='smtp.gmail.com'
                        smtp_port=587
                        server=smtplib.SMTP(smtp_server,smtp_port)
                        server.starttls()
                        ......
                        只要在创建了SMTP对象之后立即调用starttls方法 这样就创建了安全连接

                    2:接受邮件  POP3
                        接受邮件分为两步:1:用poplib 把邮件的原始文本下载到本地  2:用email解析原始文本 还原为邮件对象
                        
                        1:通过POP3 下载邮件
                            import poplib
            
                            #输入邮件地址,口令和POP3服务器地址:
                            email=raw_input('Email:...')
                            password=raw_input('Password')
                            pop3_server=raw_iinput('POP3 server..')
            
                            #连接到pop3 服务器
                            server=poplib.POP3(pop3_server)
                            #可以打开或者关闭调试信息
                            server.set_debuglevel(1)
                            #可选 打印POP3服务器欢迎文字
                            print(server.getwelcome())
                            #身份认知
                            server.user(email)
                            server.pass_(password)
                            #stat()返回邮件数量 和占用空间
                            print('Message:%s Size: %s' % server.stat())
                            #list() 返回所有邮件的编号
                            resp,mails.octets=server.list()
                            #可以查看邮件的列表 类似【1 82923  2 2184】
                            print mails
                            #获取最新的一封邮件 注意索引号从1开始
                            index=len(mails)
                            resp,lines,octets=server.retr(index)
                            #lines存储了邮件的原始文本的没一行
                            #可以获得整个邮件的原始文本
                            msg_content='\r\n'.join(lines)
                            #稍后解析邮件
                            msg=Parser().parsestr(msg_content)
                            #可以根据邮件索引号直接从服务器删除邮件
                            server.dele(index)
                            sever.quit()
                    解析邮件:
                        解析邮件的过程与发送邮件的过程正好相反 
                            import email
                            from email.parser import Parser
                            from email.header import decode_header
                            from email.utils import parseaddr
                        
                            #msg=Parser().parsestr(msg_content) 这个将邮件内容解析问一个Messge对象但是这个对象可能是MIMEMultipart 对象
                            
                            #indent用于缩进显示
                            def print_info(msg,indent=0):
                                if indent=0:
                                    #邮件的from to subject 存于根对象上
                                    for header in ['From','To','Subject']
                                        value=msg.get(header,'')
                                        if value:
                                            if header=="Subject":
                                                #需要解析subject 字符串
                                                value=decode_str(value)
                                            else:
                                                #需要解码Email地址
                                                hdr,addr=parseaddr(value)
                                                name=decode_str(hdr)
                                                value=u'%s <%s>' %(name,addr)
                                        print('%s%s:%s' % ('    '*indent,header,value))
                    
                                if (msg.is_multipart()):
                                    #如果对象是一个MIMEMultipart get_payload()返回list包含所有的子对象
                                    parts=msg.get_payload()
                                    for n,part in enumerate(parts):
                                        print('%spart %s' % ('    '*indent,n))
                                        print('%s-------------' % ('    '*indent ))
                                        #递归打印每一个子对象
                                        print_info(part,indent+1)
                                else:
                                    #邮件对象不是一个MIMEMultipart 就根据content_type判断
                                    content_type=msg.get_content_type()
                                    if content_type=='text/plain' or content_type='text/html':
                                        content=msg.get_payload(decode=True)
                                        #要检测文本编码
                                        charset=guess_charset(msg)
                                        if charset:
                                            content=content.decode(charset)
                                        print('%sText:%s' % ('    '*indent,content+'......'))
                                    else:
                                        #不是文本 作为附件处理
                                        print('%s Attachment:%s' % ('    '*indent,content_type))
            
                            def decode_str(s):
                                value,charset=decode_header(s)[0]
                                if charset:
                                    value=value.decode(charset)
                                return value

                            def guess_charset(msg):
                                #从msg对象获取编码
                                charset=msg.get_charset()
                                if charset is None:
                                    #如果没有 再从content_type 字段获取
                                    content_type=msg.get('Content-Type','').lower()
                                    pos=content_type.find('charset=')
                                    if pos>=0:
                                        charset=content_type[pos+8:].strip()
                                return charset

0 0
原创粉丝点击