Skip to content

Commit

Permalink
implicit_tls
Browse files Browse the repository at this point in the history
  • Loading branch information
mamico committed Feb 14, 2024
1 parent 9f98f83 commit ed4e9a0
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 9 deletions.
4 changes: 4 additions & 0 deletions src/zope/sendmail/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ class ISMTPMailer(IMailer):
title=_("Force TLS"),
description=_("Use TLS always for sending email."))

implicit_tls = Bool(
title=_("Implicit TLS"),
description=_("Use TLS from the beginning of the connection. force_tls and no_tls are ignored if this is set."),)


class IMaildirFactory(Interface):

Expand Down
26 changes: 17 additions & 9 deletions src/zope/sendmail/mailer.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
__docformat__ = 'restructuredtext'

from smtplib import SMTP
from smtplib import SMTP_SSL
from ssl import SSLError
from threading import local

Expand All @@ -34,17 +35,23 @@ class _SMTPState(local):
class SMTPMailer:
"""Implementation of :class:`zope.sendmail.interfaces.ISMTPMailer`."""

smtp = SMTP
smtp = None

def __init__(self, hostname='localhost', port=25,
username=None, password=None, no_tls=False, force_tls=False):
username=None, password=None, no_tls=False, force_tls=False,
implicit_tls=False):
self.hostname = hostname
self.port = port
self.username = username
self.password = password
self.force_tls = force_tls
self.no_tls = no_tls
self.implicit_tls = implicit_tls
self._smtp = _SMTPState()
# this is for backwards compatibility, in case someone has been overrided
# this class with a custom `smtp` attribute
if self.smtp is None:
self.smtp = SMTP_SSL if self.implicit_tls else SMTP

def _make_property(name):
return property(lambda self: getattr(self._smtp, name),
Expand Down Expand Up @@ -89,13 +96,14 @@ def send(self, fromaddr, toaddrs, message):
connection = self.connection

# encryption support
have_tls = connection.has_extn('starttls')
if not have_tls and self.force_tls:
raise RuntimeError('TLS is not available but TLS is required')

if have_tls and not self.no_tls:
connection.starttls()
connection.ehlo()
if not self.implicit_tls:
have_tls = connection.has_extn('starttls')
if not have_tls and self.force_tls:
raise RuntimeError('TLS is not available but TLS is required')

if have_tls and not self.no_tls:
connection.starttls()
connection.ehlo()

if connection.does_esmtp:
if self.username is not None and self.password is not None:
Expand Down

0 comments on commit ed4e9a0

Please sign in to comment.