做了一个html E-Letter项目.
邮件模板采用jinja2, html 邮件内容生成简直太爽了.
整个项目开发只用了2个小时, 调试却花了大半天时间, 生成的邮件总是发不出去.

于是, 打开 smtp 的debuglevel, 发现邮件已经mail queue了, 但就是收不到邮件. mail server是exchange. 之前用java写过类似的程序也没有问题(也是走smtp协议发送html邮件). 为什么这次用python实现却有问题?

怀疑过python smtp模块用法, 怀疑过python smtp的html写法, 怀疑过smtp subject和content不支持unicode. 最终都被排除.
最后终于定位到元凶: 邮件的subject只要包含"Please check."这13个字符, 邮件就会石沉大海. 难道是exchange server设了某种规则?

#------------------
资料:
#------------------
cnblogs 小五义的文章不错,  <<python发送各类邮件的主要方法>>,
 http://www.cnblogs.com/xiaowuyi/archive/2012/03/17/2404015.html

#------------------
代码结构
#------------------
下面简单描述一下项目的结构, 在我的脚手架项目基础上, 做了少量的裁剪, 并增加两个目录, scripts和templates, scripts目录存放E-Letter生成和发送脚本, templates目录存放E-Letter的模板.
并附上 mail_service.py, 修改了网上找的代码, 用来发送 html 邮件.

py_package
      |--scripts
               |--check1.py
               |--check2.py
      |--templates
               |--check1.html
               |--check2.html
              

# -*- coding: utf-8 -*-
#check1.py 
'''
Created on 2014-5-23 ''' 
          
from __future__ import absolute_import          
import jinja2 
from jinja2.loaders import FileSystemLoader
      
def get_template(file_name):
    '''
    get template html with jinja2 format in templates folder
    '''
    template_path=os.path.join(os.path.dirname(os.path.dirname(__file__)),'templates')
    template_env = jinja2.Environment(loader=FileSystemLoader(template_path))       
    return template_env.get_template(file_name)     
def check():
    template=get_template('check1.html')
    something='something here'
    mail_body=template.render(something=something)
    mail_sender=HtmlMailSender() 
    mail_subject='Some subject here'
    #mail_subject='Please check.'  #cannot send out, why? 
    mail_to=['a@corp.com','b.corp.com']
    mail_cc=[] 
    mail_sender.send_html_mail(mail_to,mail_cc,mail_subject,mail_body)           
    
# -*- coding: utf-8 -*-
#conf.py 
'''
Created on 2014-6-23 '''
from __future__ import absolute_import
import logging ##logging
log_level=logging.INFO   
#email setting 
smtp_host="10.10.10.10" 
smtp_port=25 
smtp_over_ssl=False
mail_user="a@corp.com" 
mail_pwd=""    # if no auth required, set pwd as empty
 
   

# -*- coding: utf-8 -*-
#mail_service.py 
'''
Created on 2014-6-23 '''
from __future__ import absolute_import
import logging
from . import conf class HtmlMailSender(object):
    logger=logging.getLogger(__name__)
    
    def __init__(self):
        #read mail settings from configure file
        self.smtp_host=conf.smtp_host
        self.smtp_port=conf.smtp_port
        self.smtp_over_ssl=conf.smtp_over_ssl
        self.mail_user=conf.mail_user
        self.mail_pwd=conf.mail_pwd        
        
        
            
    def send_html_mail(self, to_list, cc_list, subject, body):
        self.logger.info('send_html_mail() called.')
     
        import smtplib
        from email.mime.text import MIMEText  
        from email.mime.multipart import MIMEMultipart           # Construct email
        msgRoot = MIMEMultipart('related')
        msgRoot['Subject'] = subject    
        msgRoot['From'] = self.mail_user  
        msgRoot['To'] = ",".join(to_list)  
        msgRoot['CC'] =",".join(cc_list)   
        #msgRoot['BCC'] =",".join(cc_list)
        msgRoot.preamble = 'This is a multi-part message in MIME format.'
   
        # Encapsulate the plain and HTML versions of the message body in an
        # 'alternative' part, so message agents can decide which they want to display.
        msgAlternative = MIMEMultipart('alternative')
        msgRoot.attach(msgAlternative)
        
        #Add plain content
        msgText = MIMEText('This is HTML mail. If you see this message, which means you will not see the real mail content.','plain')
        msgAlternative.attach(msgText)
        
        #add html content
        msgText = MIMEText(body, 'html')
        msgAlternative.attach(msgText)
 
        try:
            if not self.smtp_over_ssl:
                if self.smtp_port=='':
                    s = smtplib.SMTP(self.smtp_host)
                else:
                    s = smtplib.SMTP(self.smtp_host, self.smtp_port)
            else:
                if self.smtp_port=='':
                    s = smtplib.SMTP_SSL(self.smtp_host)
                else:
                    s = smtplib.SMTP_SSL(self.smtp_host, self.smtp_port)
                    
            s.set_debuglevel(True)  # print stmp actions to stdout
            if self.mail_pwd :
                s.login(self.mail_user,self.mail_pwd)  
    
            to_addrs=to_list+cc_list
            s.sendmail(self.mail_user ,to_addrs, msgRoot.as_string())  
            #s.sendmail(from_addr ,to_addrs, 'test message')
            s.quit()    
            
            self.logger.info("""Mail sent. Find details below, 
            to_list: %s 
            cc_list: %s 
            subject: %s 
            body: %s"""%(to_list, cc_list, subject, body))                     
            return True  
        except Exception, ex:  
            self.logger.exception(ex)  
            return False      

用jinja做了个E-Letter小项目的更多相关文章

  1. 最近做的一个Spring Boot小项目,欢迎大家访问 http://39.97.115.152/

    最近做的一个Spring Boot小项目,欢迎大家访问 http://39.97.115.152/,帮忙找找bug,网站里有源码地址 网站说明 甲壳虫社区(Beetle Community) 一个开源 ...

  2. 小项目特供 贪吃蛇游戏(基于C语言)

    C语言写贪吃蛇本来是打算去年暑假写的,结果因为ACM集训给耽搁了,因此借寒假的两天功夫写了这个贪吃蛇小项目,顺带把C语言重温了一次. 是发表博客的前一天开始写的,一共写了三个版本,第一天写了第一版,第 ...

  3. Vue小项目二手书商城:(一)准备工作、组件和路由

    本项目基于vue2.5.2,与低版本部分不同之处会在(五)参考资料中提出 完整程序:https://github.com/M-M-Monica/bukesi 实现内容: 资源准备(mock数据) 组件 ...

  4. 用struts2标签如何从数据库获取数据并在查询页面显示。最近做一个小项目,需要用到struts2标签从数据库查询数据,并且用迭代器iterator标签在查询页面显示,可是一开始,怎么也获取不到数据,想了许久,最后发现,是自己少定义了一个变量,也就是var变量。

    最近做一个小项目,需要用到struts2标签从数据库查询数据,并且用迭代器iterator标签在查询页面显示,可是一开始,怎么也获取不到数据,想了许久,最后发现,是自己少定义了一个变量,也就是var变 ...

  5. 用原生javascript做的一个打地鼠的小游戏

    学习javascript也有一段时间了,一直以来分享的都是一些概念型的知识,今天有空做了一个打地鼠的小游戏,来跟大家分享一下,大家也可以下载来增加一些生活的乐趣,下面P出代码:首先是HTML部分代码: ...

  6. delphi 利用HTTP的POST方法做个在线翻译的小工具 good

    最近做了一个英汉小翻译的东东,用的是VC,ADO + Access访问数据库,单词数据库是从金山打字通2002弄来的.后来想了想,想再加个在线翻译的功能,记得经常使用GOOGLE翻译网站的在线翻译,也 ...

  7. 又见angular----步一步做一个angular4小项目

    这两天看了看angular4的文档,发现他和angular1.X的差别真的是太大了,官方给出的那个管理英雄的Demo是一个非常好的入门项目,这里给出一个管理个人计划的小项目,从头至尾一步一步讲解如何去 ...

  8. 在做关于NIO TCP编程小案例时遇到无法监听write的问题,没想到只是我的if语句的位置放错了位置,哎,看了半天没看出来

    在做关于NIO TCP编程小案例时遇到无法监听write的问题,没想到只是我的if语句的位置放错了位置,哎,看了半天没看出来 贴下课堂笔记: 在Java中使用NIO进行网络TCP套接字编程主要以下几个 ...

  9. 17、 利用扇贝网:https://www.shanbay.com/, 做个测单词的小工具。

    先说下,我可以说完全没有看题目要求,我只看了下扇贝网的单词测试工具就开始编码了,写出来的代码尽可能的模仿了网站上的效果. 因为把问题搞复杂了,在这个练习上耽误了很长时间,最后都不想写了,所以代码有些混 ...

  10. 毕业设计代做,各种系统微服务项目ssm项目,员工管理系统,微信小程序,购物商城,二手商城系统,销售系统,等等

    毕业设计代做,各种系统,微服务项目,ssm项目 小程序,商城等,期末作业等都可以,价格好说,长期接单, 有项目说明书,软件介绍相关文档,答辩的时候包过,知识点对接好,给你讲解等, 毕业设计代做,各种系 ...

随机推荐

  1. UVa 11384 Help is needed for Dexter

    分析题目以后得出,对于一个连续等差递增的序列,例如1,2,3,4,5,6,每次选择其中后一半,减去能减的最大数,则是最优操作. 上述序列经过一次操作后变为1,2,3,0,1,2,此时可抛弃后一半(已经 ...

  2. POJ3468 A Simple Problem with Integers

    Description 给出了一个序列,你需要处理如下两种询问. "C abc"表示给[a, b]区间中的值全部增加c (-10000 ≤ c ≤ 10000). "Q  ...

  3. Windows网络驱动、NDIS驱动(微端口驱动、中间层驱动、协议驱动)、TDI驱动(网络传输层过滤)、WFP(Windows Filtering Platform)

    catalog . 引言 . Windows 2000网络结构和OSI模型 . NDIS驱动 . NDIS微端口驱动编程实例 . NDIS中间层驱动编程实例 . NDIS协议层驱动编程实例 . TDI ...

  4. C#产生随机颜色

    在.net Framework中提供了一个专门用来产生随机数的类System.Random.C#可以用Random产生随机的R.G.B值,从而生成随机的颜色. 对于随机数,计算机不可能产生完全随机的数 ...

  5. iOS 自定义对象转NSDictionary

    我们在向后台Post数据的时候,常常需要把某个对象作为参数,比如在AF的框架中,我们进行Post时,其中的para参数就是需要NSdictionary的 Alamofire.request(.POST ...

  6. A.Kaw矩阵代数初步学习笔记 10. Eigenvalues and Eigenvectors

    “矩阵代数初步”(Introduction to MATRIX ALGEBRA)课程由Prof. A.K.Kaw(University of South Florida)设计并讲授. PDF格式学习笔 ...

  7. 使用IntelliJ IDEA和Maven构建Java web项目并打包部署

    爱编程爱分享,原创文章,转载请注明出处,谢谢! http://www.cnblogs.com/fozero/p/6120375.html 一.背景 现在越来越多的人使用IntelliJ IDEA工具进 ...

  8. wpf button的mouse(leftbutton)down/up,click事件不响应解决办法

    按照WPF的帮助说明,某些控件的路由事件被内部处理了,已经被标记为Handled,自行定义的事件处理代码便不再起作用了,有时候会很郁闷!         不过WPF提供了必要的方法.         ...

  9. python3,交互模式,无法使用ctrl和方向键,需要和ctrl一块用

    转自csdn博客 http://blog.csdn.net/pumaadamsjack/article/details/52447989 https://pypi.python.org/pypi/re ...

  10. oneM2M标准发展神速 实现万物联网的愿景

    http://m2m.iot-online.com/news/2013102224849.html oneM2M则将负责解决独立于接取网路中通用的M2M服务层的关键需求:使其可更方便地嵌入于各种软硬体 ...