diff --git a/quixote/config.py b/quixote/config.py index bd1a4fb..d75e92e 100644 --- a/quixote/config.py +++ b/quixote/config.py @@ -105,6 +105,23 @@ MAIL_FROM = None # eg. "webmaster@example.com" # this means, talk to your system administrator. MAIL_SERVER = "localhost" +# Port for email server. The default port is 25. +MAIL_PORT = None + +# If your SMTP server requires authentication, set these. +MAIL_USERNAME = None +MAIL_PASSWORD = None + +# Enable SSL for SMTP. The MAIL_PORT default will be 465. +MAIL_USE_SSL = False + +# Enable TLS for SMTP. The MAIL_PORT default will be 587. +MAIL_USE_TLS = False + +# Allow SSLv3 as a protocol. It is broken and disabled by default but +# some old mail servers require it. +MAIL_ALLOW_SSLV3 = False + # If MAIL_DEBUG_ADDR is set, then all e-mail will actually be sent to # this address rather than the intended recipients. This should be a # single, bare e-mail address. @@ -136,6 +153,12 @@ class Config: 'session_cookie_httponly', 'mail_from', 'mail_server', + 'mail_port', + 'mail_username', + 'mail_password', + 'mail_use_ssl', + 'mail_use_tls', + 'mail_allow_sslv3', 'mail_debug_addr', ] diff --git a/quixote/sendmail.py b/quixote/sendmail.py index 2ba376a..dd594d9 100644 --- a/quixote/sendmail.py +++ b/quixote/sendmail.py @@ -5,6 +5,11 @@ Tools for sending mail from Quixote applications. import email.utils from email.header import Header from smtplib import SMTP +try: + from smtplib import SMTP_SSL + import ssl +except ImportError: + ssl = None import quixote EMAIL_ENCODING = 'utf-8' @@ -121,7 +126,8 @@ def sendmail(subject, msg_body, to_addrs, extra_headers=None, smtp_sender=None, smtp_recipients=None, mail_server=None, mail_debug_addr=None, - config=None): + username=None, password=None, mail_port=None, + use_ssl=False, use_tls=False, config=None): """ Send an email message to a list of recipients via a local SMTP server. In normal use, you supply a list of primary recipient @@ -197,6 +203,11 @@ def sendmail(subject, msg_body, to_addrs, mail_server = mail_server or config.mail_server if config is not None: mail_debug_addr = mail_debug_addr or config.mail_debug_addr + username = username or config.mail_username + password = password or config.mail_password + mail_port = mail_port or config.mail_port + use_ssl = use_ssl or config.mail_use_ssl + use_tls = use_tls or config.mail_use_tls if not isinstance(to_addrs, list): raise TypeError("'to_addrs' must be a list") @@ -263,6 +274,31 @@ def sendmail(subject, msg_body, to_addrs, # smtplib requires bytes message = message.encode(EMAIL_ENCODING) - smtp = SMTP(mail_server) + if not mail_port: + if use_ssl: + mail_port = 465 + elif use_tls: + mail_port = 587 + else: + mail_port = 25 + + if ssl and (use_ssl or use_tls): + context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) + if config and config.mail_allow_sslv3: + # need to allow SSLv3 for old servers, even though it is broken + context.options &= ~ssl.OP_NO_SSLv3 + else: + context = None + + if use_ssl: + smtp = SMTP_SSL(mail_server, port=mail_port, context=context) + else: + smtp = SMTP(mail_server, port=mail_port) + smtp.ehlo() + if use_tls: + smtp.starttls(context=context) + smtp.ehlo() + if username: + smtp.login(username, password) smtp.sendmail(smtp_sender, smtp_recipients, message) smtp.quit()