3434import logging
3535import re
3636import smtplib
37-
37+ import ssl
3838from email .mime .multipart import MIMEMultipart
3939from email .mime .text import MIMEText
4040from email .mime .image import MIMEImage
4141
42-
4342class VscMailError (Exception ):
4443 """Raised if the sending of an email fails for some reason."""
4544
@@ -68,14 +67,43 @@ def __init__(self, mail_host=None, mail_to=None, mail_from=None, mail_subject=No
6867class VscMail (object ):
6968 """Class providing functionality to send out mail."""
7069
71- def __init__ (self , mail_host = None ):
70+ def __init__ (
71+ self ,
72+ mail_host = '' ,
73+ mail_port = 0 ,
74+ smtp_auth_user = None ,
75+ smtp_auth_password = None ,
76+ smtp_use_starttls = False ):
77+
7278 self .mail_host = mail_host
79+ self .mail_port = mail_port
80+ self .smtp_auth_user = smtp_auth_user
81+ self .smtp_auth_password = smtp_auth_password
82+ self .smtp_use_starttls = smtp_use_starttls
83+
84+ def _connect (self ):
85+ """
86+ Connect to the mail host on the given port.
87+
88+ If provided, use authentication and TLS.
89+ """
90+ logging .debug ("Using mail host %s, mail port %d" , self .mail_host , self .mail_port )
91+ s = smtplib .SMTP (host = self .mail_host , port = self .mail_port )
7392
74- def _send (self ,
75- mail_from ,
76- mail_to ,
77- mail_subject ,
78- msg ):
93+ if self .smtp_use_starttls :
94+ context = ssl .create_default_context ()
95+ s .starttls (context = context )
96+ logging .debug ("Started TLS connection" )
97+
98+ if self .smtp_auth_user and self .smtp_auth_password :
99+ s .login (user = self .smtp_auth_user , password = self .smtp_auth_password )
100+ logging .debug ("Authenticated" )
101+
102+ s .connect ()
103+
104+ return s
105+
106+ def _send (self , mail_from , mail_to , mail_subject , msg ):
79107 """Actually send the mail.
80108
81109 @type mail_from: string representing the sender.
@@ -85,13 +113,8 @@ def _send(self,
85113 """
86114
87115 try :
88- if self .mail_host :
89- logging .debug ("Using %s as the mail host" , self .mail_host )
90- s = smtplib .SMTP (self .mail_host )
91- else :
92- logging .debug ("Using the default mail host" )
93- s = smtplib .SMTP ()
94- s .connect ()
116+ s = self ._connect ()
117+
95118 try :
96119 s .sendmail (mail_from , mail_to , msg .as_string ())
97120 except smtplib .SMTPHeloError as err :
@@ -105,27 +128,27 @@ def _send(self,
105128 raise
106129 except smtplib .SMTPDataError as err :
107130 raise
131+
108132 except smtplib .SMTPConnectError as err :
109133 logging .exception ("Cannot connect to the SMTP host %s" , self .mail_host )
110- raise VscMailError (mail_host = self .mail_host ,
111- mail_to = mail_to ,
112- mail_from = mail_from ,
113- mail_subject = mail_subject ,
114- err = err )
134+ raise VscMailError (
135+ mail_host = self .mail_host ,
136+ mail_to = mail_to ,
137+ mail_from = mail_from ,
138+ mail_subject = mail_subject ,
139+ err = err )
115140 except Exception as err :
116141 logging .exception ("Some unknown exception occurred in VscMail.sendTextMail. Raising a VscMailError." )
117- raise VscMailError (mail_host = self .mail_host ,
118- mail_to = mail_to ,
119- mail_from = mail_from ,
120- mail_subject = mail_subject ,
121- err = err )
122-
123- def sendTextMail (self ,
124- mail_to ,
125- mail_from ,
126- reply_to ,
127- mail_subject ,
128- message ):
142+ raise VscMailError (
143+ mail_host = self .mail_host ,
144+ mail_to = mail_to ,
145+ mail_from = mail_from ,
146+ mail_subject = mail_subject ,
147+ err = err )
148+ else :
149+ s .quit ()
150+
151+ def sendTextMail (self , mail_to , mail_from , reply_to , mail_subject , message ):
129152 """Send out the given message by mail to the given recipient(s).
130153
131154 @type mail_to: string or list of strings
@@ -174,15 +197,16 @@ def _replace_images_cid(self, html, images):
174197
175198 return html
176199
177- def sendHTMLMail (self ,
178- mail_to ,
179- mail_from ,
180- reply_to ,
181- mail_subject ,
182- html_message ,
183- text_alternative ,
184- images = None ,
185- css = None ):
200+ def sendHTMLMail (
201+ self ,
202+ mail_to ,
203+ mail_from ,
204+ reply_to ,
205+ mail_subject ,
206+ html_message ,
207+ text_alternative ,
208+ images = None ,
209+ css = None ):
186210 """
187211 Send an HTML email message, encoded in a MIME/multipart message.
188212
@@ -222,7 +246,7 @@ def sendHTMLMail(self,
222246
223247 # Create the body of the message (a plain-text and an HTML version).
224248 if images is not None :
225- html_message = self .replace_images_cid (html_message , images )
249+ html_message = self ._replace_images_cid (html_message , images )
226250
227251 # Record the MIME types of both parts - text/plain and text/html_message.
228252 msg_plain = MIMEText (text_alternative , 'plain' )
0 commit comments