1
2 """
3 mailer module
4
5 Simple front end to the smtplib and email modules,
6 to simplify sending email.
7
8 A lot of this code was taken from the online examples in the
9 email module documentation:
10 http://docs.python.org/library/email-examples.html
11
12 Released under MIT license.
13
14 Version 0.5 is based on a patch by Douglas Mayle
15
16 Sample code:
17
18 import mailer
19
20 message = mailer.Message()
21 message.From = "me@example.com"
22 message.To = "you@example.com"
23 message.Subject = "My Vacation"
24 message.Body = open("letter.txt", "rb").read()
25 message.attach("picture.jpg")
26
27 sender = mailer.Mailer('mail.example.com')
28 sender.send(message)
29
30 """
31 import smtplib
32
33
34
35 try:
36 from email import encoders
37 from email.header import make_header
38 from email.message import Message
39 from email.mime.audio import MIMEAudio
40 from email.mime.base import MIMEBase
41 from email.mime.image import MIMEImage
42 from email.mime.multipart import MIMEMultipart
43 from email.mime.text import MIMEText
44 except ImportError:
45 from email import Encoders as encoders
46 from email.Header import make_header
47 from email.MIMEMessage import Message
48 from email.MIMEAudio import MIMEAudio
49 from email.MIMEBase import MIMEBase
50 from email.MIMEImage import MIMEImage
51 from email.MIMEMultipart import MIMEMultipart
52 from email.MIMEText import MIMEText
53
54
55 import mimetypes
56
57 from os import path
58
59 __version__ = "0.5"
60 __author__ = "Ryan Ginstrom"
61 __license__ = "MIT"
62 __description__ = "A module to send email simply in Python"
63
65 """
66 Represents an SMTP connection.
67
68 Use login() to log in with a username and password.
69 """
70
71 - def __init__(self, host="localhost", port=0):
72 self.host = host
73 self.port = port
74 self._usr = None
75 self._pwd = None
76
77 - def login(self, usr, pwd):
78 self._usr = usr
79 self._pwd = pwd
80
81 - def send(self, msg):
82 """
83 Send one message or a sequence of messages.
84
85 Every time you call send, the mailer creates a new
86 connection, so if you have several emails to send, pass
87 them as a list:
88 mailer.send([msg1, msg2, msg3])
89 """
90 server = smtplib.SMTP(self.host, self.port)
91
92 if self._usr and self._pwd:
93 server.login(self._usr, self._pwd)
94
95 try:
96 num_msgs = len(msg)
97 for m in msg:
98 self._send(server, m)
99 except TypeError:
100 self._send(server, msg)
101
102 server.quit()
103
104 - def _send(self, server, msg):
105 """
106 Sends a single message using the server
107 we created in send()
108 """
109 me = msg.From
110 if isinstance(msg.To, basestring):
111 you = [msg.To]
112 else:
113 you = list(msg.To)
114 server.sendmail(me, you, msg.as_string())
115
117 """
118 Represents an email message.
119
120 Set the To, From, Subject, and Body attributes as plain-text strings.
121 Optionally, set the Html attribute to send an HTML email, or use the
122 attach() method to attach files.
123
124 Use the charset property to send messages using other than us-ascii
125
126 If you specify an attachments argument, it should be a list of
127 attachment filenames: ["file1.txt", "file2.txt"]
128
129 `To` should be a string for a single address, and a sequence
130 of strings for multiple recipients (castable to list)
131
132 Send using the Mailer class.
133 """
134
135 - def __init__(self, To=None, From=None, Subject=None, Body=None, Html=None,
136 attachments=None, charset=None):
137 self.attachments = []
138 if attachments:
139 for attachment in attachments:
140 if isinstance(attachment, basestring):
141 self.attachments.append((attachment, None))
142 else:
143 try:
144 filename, cid = attachment
145 except (TypeError, IndexError):
146 self.attachments.append((attachment, None))
147 else:
148 self.attachments.append((filename, cid))
149 self.To = To
150 """string or iterable"""
151 self.From = From
152 """string"""
153 self.Subject = Subject
154 self.Body = Body
155 self.Html = Html
156 self.charset = charset or 'us-ascii'
157
159 """Get the email as a string to send in the mailer"""
160
161 if not self.attachments:
162 return self._plaintext()
163 else:
164 return self._multipart()
165
166 - def _plaintext(self):
167 """Plain text email with no attachments"""
168
169 if not self.Html:
170 msg = MIMEText(self.Body, 'plain', self.charset)
171 else:
172 msg = self._with_html()
173
174 self._set_info(msg)
175 return msg.as_string()
176
178 """There's an html part"""
179
180 outer = MIMEMultipart('alternative')
181
182 part1 = MIMEText(self.Body, 'plain', self.charset)
183 part2 = MIMEText(self.Html, 'html', self.charset)
184
185 outer.attach(part1)
186 outer.attach(part2)
187
188 return outer
189
191 if self.charset == 'us-ascii':
192 msg['Subject'] = self.Subject
193 else:
194 subject = unicode(self.Subject, self.charset)
195 msg['Subject'] = str(make_header([(subject, self.charset)]))
196 msg['From'] = self.From
197 if isinstance(self.To, basestring):
198 msg['To'] = self.To
199 else:
200 self.To = list(self.To)
201 msg['To'] = ", ".join(self.To)
202
204 """The email has attachments"""
205
206 msg = MIMEMultipart('related')
207
208 if self.Html:
209 outer = MIMEMultipart('alternative')
210
211 part1 = MIMEText(self.Body, 'plain', self.charset)
212 part1.add_header('Content-Disposition', 'inline')
213
214 part2 = MIMEText(self.Html, 'html', self.charset)
215 part2.add_header('Content-Disposition', 'inline')
216
217 outer.attach(part1)
218 outer.attach(part2)
219 msg.attach(outer)
220 else:
221 msg.attach(MIMEText(self.Body, 'plain', self.charset))
222
223 self._set_info(msg)
224 msg.preamble = self.Subject
225
226 for filename, cid in self.attachments:
227 self._add_attachment(msg, filename, cid)
228
229 return msg.as_string()
230
232 ctype, encoding = mimetypes.guess_type(filename)
233 if ctype is None or encoding is not None:
234
235
236 ctype = 'application/octet-stream'
237 maintype, subtype = ctype.split('/', 1)
238 fp = open(filename, 'rb')
239 if maintype == 'text':
240
241 msg = MIMEText(fp.read(), _subtype=subtype)
242 elif maintype == 'image':
243 msg = MIMEImage(fp.read(), _subtype=subtype)
244 elif maintype == 'audio':
245 msg = MIMEAudio(fp.read(), _subtype=subtype)
246 else:
247 msg = MIMEBase(maintype, subtype)
248 msg.set_payload(fp.read())
249
250 encoders.encode_base64(msg)
251 fp.close()
252
253
254 if cid:
255 msg.add_header('Content-ID', '<%s>' % cid)
256 msg.add_header('Content-Disposition', 'inline')
257 else:
258
259 msg.add_header('Content-Disposition', 'attachment', filename=path.basename(filename))
260 outer.attach(msg)
261
262 - def attach(self, filename, cid=None):
263 """
264 Attach a file to the email. Specify the name of the file;
265 Message will figure out the MIME type and load the file.
266 """
267
268 self.attachments.append((filename, cid))
269