1 #- * - encoding: utf-8 - * -
3 # module for class SMTPServer
10 from email
import encoders
11 from email
.mime
.audio
import MIMEAudio
12 from email
.mime
.base
import MIMEBase
13 from email
.mime
.image
import MIMEImage
14 from email
.mime
.multipart
import MIMEMultipart
15 from email
.mime
.text
import MIMEText
16 from email
.utils
import make_msgid
19 """ class SMTPServer is the infomation about a SMTP Server, include
20 email,user:passwd@addr:port ssl,
21 So you can MailBigFile, and MailFiles by it """
22 def __init__(self
,email
='r01ustc@gmail.com',ip
='localhost',port
=25,ssl
=0,username
='',password
=''):
30 """ override the str(), used often by print """
39 return 'E-Mail:'+self
.email
+'\n' \
40 +'Server:'+self
.addr
+':%d(%s)\n'%(self
.port
,sslmsg
) \
41 +'User,Pass:'+self
.user
+','+self
.passwd
42 # info=[addr,port,ssl,username,password,mailaddress]
43 def SetInfoFromList(self
,info
):
44 """ Set Information of SMTP Server in a list """
51 def SetInfo(self
,email
='r01ustc@gmail.com',ip
='localhost',port
=25,ssl
=0,username
='',password
=''):
52 """ Set Infomation of SMTP Server """
60 def SendMail(self
,tolist
,msg
):
61 """ Send msg to tolist.
62 tolist: the list of recipients
63 msg: formatted mail message"""
64 print 'From:'+self
.email
67 s
=smtplib
.SMTP(self
.addr
,self
.port
)
69 s
=smtpssl
.SMTP_SSL(self
.addr
,self
.port
)
71 s
=smtplib
.SMTP(self
.addr
,self
.port
)
78 s
.login(self
.user
,self
.passwd
)
79 s
.sendmail(self
.email
,tolist
,msg
)
81 def MailFiles(self
,tolist
,subject
,bodymsg
, mailattachlist
=[],charset
=None):
83 tolist: the address list where we mailed to,['a@b.c','c@d.e']
84 subject: the subject, used it directly. If you want to use utf-8
85 charset, please use email.Header.Header(msg,charset) to
87 bodymsg: the mail body, it is a list, and the first item is pure text,
88 the second item is html
89 mailattachlist is the attached file list,['a.txt','b.exe','c.jpg']
90 charset : give the charset of mailattachlist file name"""
92 # 创建一个multipart, 然后把前面的文本部分和html部分都附加到上面,至于为什么,可以看看mime相关内容
93 attach
=email
.MIMEMultipart
.MIMEMultipart()
94 # head = email.Message.Message()
95 attach
['Message-ID']=make_msgid()
96 attach
['From']=self
.email
97 if type(tolist
)==type([]): #if tolist is a list
98 attach
['To']=', '.join(tolist
)
99 else: # tolist is only a string
101 attach
['Subject']=subject
# email.Header.Header(subject,'utf-8')
102 if type(bodymsg
)==type([]): # if bodymsg is a list
104 body_plain
= email
.MIMEText
.MIMEText(bodymsg
[0], _subtype
='plain', _charset
='utf-8')
108 body_html
= email
.MIMEText
.MIMEText(bodymsg
[1], _subtype
='html', _charset
='utf-8')
109 else: #bodymsg is a string
111 body_plain
= email
.MIMEText
.MIMEText(bodymsg
, _subtype
='plain', _charset
='utf-8')
113 attach
.attach(body_plain
)
115 attach
.attach(body_html
)
117 for fname
in mailattachlist
:
118 ctype
, encoding
= mimetypes
.guess_type(fname
)
119 if ctype
is None or encoding
is not None:
120 # No guess could be made, or the file is encoded (compressed), so
121 # use a generic bag-of-bits type.
122 ctype
= 'application/octet-stream'
123 maintype
, subtype
= ctype
.split('/', 1)
124 filebasename
=os
.path
.basename(fname
)
125 if maintype
== 'text':
127 # Note: we should handle calculating the charset
128 msg
= MIMEText(fp
.read(), _subtype
=subtype
)
130 # msg.add_header('Content-Disposition', 'attachment', filename=os.path.basename(fname))
131 elif maintype
== 'image':
132 fp
= open(fname
, 'rb')
133 msg
= MIMEImage(fp
.read(), _subtype
=subtype
)
135 # msg.add_header('Content-Disposition', 'attachment', filename=os.path.basename(fname))
136 elif maintype
== 'audio':
137 fp
= open(fname
, 'rb')
138 msg
= MIMEAudio(fp
.read(), _subtype
=subtype
)
140 # msg.add_header('Content-Disposition', 'attachment', filename=os.path.basename(fname))
142 fp
= open(fname
, 'rb')
143 msg
= MIMEBase(maintype
, subtype
)
144 msg
.set_payload(fp
.read())
146 # Encode the payload using Base64
147 encoders
.encode_base64(msg
)
148 filebasename
=filebasename
+'.a'
149 if charset
: # if give the charset, we format the filename
150 ffname
=str(email
.Header
.Header(filebasename
,charset
))
151 else: # else , just use the original name
153 print 'Formatted filename in MailFiles:'+ffname
154 msg
.add_header('Content-Disposition', 'attachment', filename
=ffname
)
157 mail
= attach
.as_string()
159 self
.SendMail(tolist
,mail
)
163 def CreateFilePartMail(self
,to
,subject
,bodymsg
,fp
,filename
,lbegin
,lend
,icount
):
164 """ Mail Part of the file with name filename,
166 filename is the filename, please formatted yourself first,
167 You can use email.Header.Header(str,charset) to do it
168 lbegin is the begin position of file
169 lend is the end position of file,
170 icount is the count number for the part of file, 20
171 to is the address list where we mailed to,['a@b.c','c@d.e']
172 subject is the subject, please formatted yourself first to support utf-8
174 bodymsg is the mailbody, it is a list, and the first item is pure text,
175 where the second item is html """
176 attmsg
=MIMEBase('application','octet-stream')
178 attmsg
.set_payload(fp
.read(lend
-lbegin
))
179 encoders
.encode_base64(attmsg
)
180 attmsg
.add_header('Content-Disposition', 'attachment', filename
=filename
)
181 msg
=email
.MIMEMultipart
.MIMEMultipart()
182 # head=email.Message.Message()
183 msg
['From']=self
.email
184 msg
['Message-ID']=make_msgid()
185 if type(to
)==type([]): # if to is a list
186 msg
['To']=', '.join(to
)
187 else: # to is a single string
189 msg
['Subject']=subject
192 if type(bodymsg
)==type([]): #bodymsg is a list
193 body_plain
= email
.MIMEText
.MIMEText(bodymsg
[0], _subtype
='plain', _charset
='utf-8')
194 msg
.attach(body_plain
)
198 body_html
= email
.MIMEText
.MIMEText(bodymsg
[1], _subtype
='html', _charset
='utf-8')
199 msg
.attach(body_html
)
200 else: # bodymsg is a single string
201 body_plain
= email
.MIMEText
.MIMEText(bodymsg
, _subtype
='plain', _charset
='utf-8')
202 msg
.attach(body_plain
)
205 return msg
.as_string()
207 # split big file to several mail
208 def MailBigFile(self
,tolist
,subject
,bodymsg
,filename
,leneach
,ffname
=None):
209 """ Mail a big file by splitting it into pieces then mail,
210 tolist is the address list where we mailed to,['a@b.c','c@d.e']
211 subject is the subject
212 bodymsg is the mailbody, it is a list, and the first item is pure text,
213 where the second item is html
214 filename is the big filename, it will appeared in body message
215 leneach is the len of file piece
216 ffname: formatted filename, used to give utf-8 charset name,
217 you can formatted the filename by email.Header.Header(str,charset), if None, just use the basename(filename)"""
219 filelen
=os
.stat(filename
).st_size
220 # lmaxpiece gives the number of file pieces
221 lmaxpiece
=filelen
/leneach
222 if(lmaxpiece
*leneach
< filelen
):
223 lmaxpiece
=lmaxpiece
+1
227 fp
=open(filename
,'rb') # openfile
229 if type(bodymsg
)==type([]): # if body is a list
230 bodymsg
[0]=filename
+'\n part %d/%d'%(i
+1,lmaxpiece
)
231 else: # body is a single string
232 bodymsg
=filename
+'\n part %d/%d'%(i
+1,lmaxpiece
)
233 if not ffname
: # if ffname=None
234 ffilename
=os
.path
.basename(filename
)+'.%03d'%(i
+1)
236 ffilename
=ffname
+'.%03d'%(i
+1)
237 print 'formatted file name in MailBigFile:'+ffilename
238 s
=self
.CreateFilePartMail(tolist
,subject
,bodymsg
,fp
,ffilename
,lbegin
,lend
,i
+1)
239 self
.SendMail(tolist
,s
)
249 """ This class is used to manage SMTPServer list """
250 def __init__(self
,dict,default
=None):
251 """ dict has the form: {name:[addr,port,ssl,username,password,mailaddress]} """
254 self
.names
=dict.keys()
258 self
.current
=self
.names
[0]
261 self
.Subject
='XMailer: tool to mail multifile'
263 def OnlyDefault(self
,od
=0):
264 """ if onlydefault, we use the default SMTP Sender, else use all Servers"""
267 def SetCharset(self
,charset
=None):
268 ''' set up the charset, default is None, can be like 'utf-8' to deal with chinese '''
271 def SetSubject(self
,subj
,charset
=None):
273 self
.Subject
=email
.Header
.Header(subj
,charset
)
275 self
.Subject
=email
.Header
.Header(subj
,self
.charset
)
279 """ get the Next Server """
282 keylen
=len(self
.names
)
283 for i
in range(0,keylen
):
284 if self
.names
[i
]==self
.current
:
290 self
.current
=self
.names
[i
]
291 print 'Current:'+self
.current
294 def CreateBodyMail(self
,bodymsg
,charset
=None):
295 """ Create txt MIME part, listed in bodylist
296 bodylist can be a list or a single string"""
298 if type(bodymsg
)==type([]): # if bodymsg is a list
300 body_plain
= email
.MIMEText
.MIMEText(bodymsg
[0], _subtype
='plain', _charset
=charset
)
303 body_html
= email
.MIMEText
.MIMEText(bodymsg
[1], _subtype
='html', _charset
=charset
)
304 else: #bodymsg is a string
306 body_plain
= email
.MIMEText
.MIMEText(bodymsg
, _subtype
='plain', _charset
=charset
)
308 return [body_plain
,body_html
]
312 # MIME parts contain every file in attachlist
313 def CreateFilesMail(self
,attachlist
=[],charset
=None):
314 """ create a list of MIME parts, which encode every file list in attachlist,
315 charset: the charset of name in attachlist"""
318 for fname
in attachlist
:
319 ctype
, encoding
= mimetypes
.guess_type(fname
)
320 if ctype
is None or encoding
is not None:
321 # No guess could be made, or the file is encoded (compressed),
322 # so use a generic bag-of-bits type.
323 ctype
= 'application/octet-stream'
324 maintype
, subtype
= ctype
.split('/', 1)
325 # print 'MIME type:',maintype,subtype
326 filebasename
=os
.path
.basename(fname
)
327 if maintype
== 'text':
329 # Note: we should handle calculating the charset
330 msg
= MIMEText(fp
.read(), _subtype
=subtype
)
332 elif maintype
== 'image':
333 fp
= open(fname
, 'rb')
334 msg
= MIMEImage(fp
.read(), _subtype
=subtype
)
336 elif maintype
== 'audio':
337 fp
= open(fname
, 'rb')
338 msg
= MIMEAudio(fp
.read(), _subtype
=subtype
)
341 maintype
,subtype
='application','octet-stream'
342 fp
= open(fname
, 'rb')
343 msg
= MIMEBase(maintype
, subtype
)
344 msg
.set_payload(fp
.read())
345 # Encode the payload using Base64
346 encoders
.encode_base64(msg
)
348 filebasename
=filebasename
+'.a'
349 if charset
: # if give the charset, we format the filename
350 ffname
=str(email
.Header
.Header(filebasename
,charset
))
351 else: # else , just use the original name
353 # print 'Formatted filename in MailFiles:'+ffname
354 msg
.add_header('Content-Disposition', 'attachment', filename
=ffname
)
358 # MIME part contain part of file
359 def CreateFilePartMail(self
,fp
,lbegin
,lend
,filename
):
360 """ Mail Part of the file with name filename,
362 filename is the filename, please formatted yourself first,
363 You can use email.Header.Header(str,charset) to do it
364 lbegin is the begin position of file
365 lend is the end position of file """
366 attmsg
=MIMEBase('application','octet-stream')
368 attmsg
.set_payload(fp
.read(lend
-lbegin
))
369 encoders
.encode_base64(attmsg
)
370 attmsg
.add_header('Content-Disposition', 'attachment', filename
=filename
)
374 def MailFiles(self
,tolist
,subject
,bodylist
,filelist
,bcc
=None,charset
=None):
375 """ mail files in filelist to tolist+bcc,
376 tolist: list contains the recipients
377 subject: subject of the mail, already formatted
378 bodylist: list contains the message body, it is MIME part
379 filelist: list contains the file we want to mail.
380 bcc: BCC fields, contains the recipients which not show in mail."""
382 # print 'to',tolist,'bcc',bcc
384 msg
=email
.MIMEMultipart
.MIMEMultipart()
385 # head = email.Message.Message()
386 msg
['Message-ID']=make_msgid()
387 if type(tolist
)==type([]): #if tolist is a list
388 msg
['To']=', '.join(tolist
)
389 recipients
=tolist
[0:]
390 else: # tolist is only a string
393 if bcc
: # bcc is not empty
394 if type(bcc
)==type([]):
395 recipients
.extend(bcc
)
397 recipients
.append(bcc
)
398 print 'recipients:',recipients
399 msg
['Subject']=subject
# email.Header.Header(subject,'utf-8')
400 if type(bodylist
)==type([]):
405 flist
=self
.CreateFilesMail(filelist
,charset
)
408 sender
.SetInfoFromList(self
.serdict
[self
.current
])
409 msg
['From']=sender
.email
410 sender
.SendMail(recipients
,msg
.as_string())
413 def MailBigFile(self
,tolist
,subject
,bodylist
,pathname
,leneach
,bcc
=None,charset
=None):
414 """ mail a big file to tolist+bcc,
415 tolist: list contains the recipients
416 subject: subject formatted
417 bodylist: contains the message, which maybe the infomation of the file
418 pathname: full path name of the file
419 leneach: len of each mail
424 if type(tolist
)==type([]): # if to is a list
425 headto
=', '.join(tolist
)
426 recipients
=tolist
[0:]
427 else: # to is a single string
431 if type(bcc
)==type([]):
432 recipients
.extend(bcc
)
434 recipients
.append(bcc
)
437 ffname
=str(email
.Header
.Header(os
.path
.basename(pathname
),charset
))
439 ffname
=os
.path
.basename(pathname
)
441 filelen
=os
.stat(pathname
).st_size
442 # lmaxpiece gives the number of file pieces
443 lmaxpiece
=filelen
/leneach
444 if(lmaxpiece
*leneach
< filelen
):
445 lmaxpiece
=lmaxpiece
+1
449 fp
=open(pathname
,'rb') # openfile
451 ffilename
=ffname
+'.%03d'%(i
+1)
452 print 'formatted file name in MailBigFile:'+ffilename
453 msg
=email
.MIMEMultipart
.MIMEMultipart()
454 if type(bodylist
)==type([]):
455 for msgi
in bodylist
:
459 msg
.attach(self
.CreateFilePartMail(fp
,lbegin
,lend
,ffilename
))
460 sender
.SetInfoFromList(self
.serdict
[self
.current
])
462 msg
['Subject']=subject
463 msg
['From']=sender
.email
464 msg
['Message-ID']=make_msgid()
465 sender
.SendMail(recipients
,msg
.as_string())