Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[9740] ESMTPSender: dont't force TLSv1.0 by default #1225

Merged
merged 8 commits into from
Mar 28, 2020
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/twisted/mail/newsfragments/9740.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
twisted.mail.smtp.ESMTPSender no longer forces TLSv1.0 when used without explicit context factory.
43 changes: 33 additions & 10 deletions src/twisted/mail/smtp.py
Original file line number Diff line number Diff line change
Expand Up @@ -1196,7 +1196,7 @@ class ESMTPClient(SMTPClient):
@type requireAuthentication: L{bool}

@ivar context: The context factory to use for STARTTLS, if desired.
@type context: L{ssl.ClientContextFactory}
@type context: L{IOpenSSLClientConnectionCreator}

@ivar _tlsMode: Whether or not the connection is over TLS.
@type _tlsMode: L{bool}
Expand Down Expand Up @@ -2010,6 +2010,11 @@ def __init__(self, username, secret, contextFactory=None, *args, **kw):
self.heloFallback = 0
self.username = username

self._hostname = None
mmilata marked this conversation as resolved.
Show resolved Hide resolved
if 'hostname' in kw:
self._hostname = kw['hostname']
del kw['hostname']

if contextFactory is None:
contextFactory = self._getContextFactory()

Expand All @@ -2028,14 +2033,15 @@ def _registerAuthenticators(self):
def _getContextFactory(self):
if self.context is not None:
return self.context
if self._hostname is None:
return None
try:
from twisted.internet import ssl
from twisted.internet._sslverify import optionsForClientTLS
mmilata marked this conversation as resolved.
Show resolved Hide resolved
except ImportError:
return None
else:
try:
context = ssl.ClientContextFactory()
context.method = ssl.SSL.TLSv1_METHOD
context = optionsForClientTLS(self._hostname)
return context
except AttributeError:
mmilata marked this conversation as resolved.
Show resolved Hide resolved
return None
Expand All @@ -2056,15 +2062,18 @@ def __init__(self, username, password, fromEmail, toEmail, file,
deferred, retries=5, timeout=None,
contextFactory=None, heloFallback=False,
requireAuthentication=True,
requireTransportSecurity=True):
requireTransportSecurity=True,
hostname=None):

SMTPSenderFactory.__init__(self, fromEmail, toEmail, file, deferred, retries, timeout)
SMTPSenderFactory.__init__(self, fromEmail, toEmail, file, deferred,
retries, timeout)
self.username = username
self.password = password
self._contextFactory = contextFactory
self._heloFallback = heloFallback
self._requireAuthentication = requireAuthentication
self._requireTransportSecurity = requireTransportSecurity
self._hostname = hostname


def buildProtocol(self, addr):
Expand All @@ -2078,7 +2087,8 @@ def buildProtocol(self, addr):
@rtype: L{ESMTPSender}
"""
p = self.protocol(self.username, self.password, self._contextFactory,
self.domain, self.nEmails*2+2)
self.domain, self.nEmails*2+2,
hostname=self._hostname)
p.heloFallback = self._heloFallback
p.requireAuthentication = self._requireAuthentication
p.requireTransportSecurity = self._requireTransportSecurity
Expand Down Expand Up @@ -2179,9 +2189,22 @@ def cancel(d):
if isinstance(password, unicode):
password = password.encode("utf-8")

factory = ESMTPSenderFactory(username, password, from_addr, to_addrs, msg,
d, heloFallback=True, requireAuthentication=requireAuthentication,
requireTransportSecurity=requireTransportSecurity)
tlsHostname = smtphost
if not isinstance(tlsHostname, unicode):
tlsHostname = tlsHostname.decode("ascii")
mmilata marked this conversation as resolved.
Show resolved Hide resolved

factory = ESMTPSenderFactory(
username,
password,
from_addr,
to_addrs,
msg,
d,
heloFallback=True,
requireAuthentication=requireAuthentication,
requireTransportSecurity=requireTransportSecurity,
hostname=tlsHostname
)

if senderDomainName is not None:
factory.domain = networkString(senderDomainName)
Expand Down