標籤:style class blog code java http
做了一個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=[‘[email protected]‘,‘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="[email protected]"
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