Kaydet (Commit) 2539e674 authored tarafından R David Murray's avatar R David Murray

#21725: Add RFC 6531 (SMTPUTF8) support to smtpd.

Patch by Milan Oberkirch, developed as part of his 2014 GSOC project.

Note that this also fixes a bug in mock_socket ('getpeername' was returning a
simple string instead of the tuple required for IPvX protocols), a bug in
DebugServer with respect to handling binary data (should have been fixed when
decode_data was introduced, but wasn't found until this patch was written),
and a long-standing bug in DebugServer (it was printing an extra blank line at
the end of the displayed message text).
üst ae04ba19
...@@ -20,7 +20,8 @@ specific mail-sending strategies. ...@@ -20,7 +20,8 @@ specific mail-sending strategies.
Additionally the SMTPChannel may be extended to implement very specific Additionally the SMTPChannel may be extended to implement very specific
interaction behaviour with SMTP clients. interaction behaviour with SMTP clients.
The code supports :RFC:`5321`, plus the :rfc:`1870` SIZE extension. The code supports :RFC:`5321`, plus the :rfc:`1870` SIZE and :rfc:`6531`
SMTPUTF8 extensions.
SMTPServer Objects SMTPServer Objects
...@@ -28,7 +29,7 @@ SMTPServer Objects ...@@ -28,7 +29,7 @@ SMTPServer Objects
.. class:: SMTPServer(localaddr, remoteaddr, data_size_limit=33554432,\ .. class:: SMTPServer(localaddr, remoteaddr, data_size_limit=33554432,\
map=None, decode_data=True) map=None, enable_SMTPUTF8=False, decode_data=True)
Create a new :class:`SMTPServer` object, which binds to local address Create a new :class:`SMTPServer` object, which binds to local address
*localaddr*. It will treat *remoteaddr* as an upstream SMTP relayer. It *localaddr*. It will treat *remoteaddr* as an upstream SMTP relayer. It
...@@ -39,6 +40,12 @@ SMTPServer Objects ...@@ -39,6 +40,12 @@ SMTPServer Objects
accepted in a ``DATA`` command. A value of ``None`` or ``0`` means no accepted in a ``DATA`` command. A value of ``None`` or ``0`` means no
limit. limit.
*enable_SMTPUTF8* determins whether the ``SMTPUTF8`` extension (as defined
in :RFC:`6531`) should be enabled. The default is ``False``. If
*enable_SMTPUTF* is set to ``True``, the :meth:`process_smtputf8_message`
method must be defined. A :exc:`ValueError` is raised if both
*enable_SMTPUTF8* and *decode_data* are set to ``True`` at the same time.
A dictionary can be specified in *map* to avoid using a global socket map. A dictionary can be specified in *map* to avoid using a global socket map.
*decode_data* specifies whether the data portion of the SMTP transaction *decode_data* specifies whether the data portion of the SMTP transaction
...@@ -48,18 +55,32 @@ SMTPServer Objects ...@@ -48,18 +55,32 @@ SMTPServer Objects
.. method:: process_message(peer, mailfrom, rcpttos, data) .. method:: process_message(peer, mailfrom, rcpttos, data)
Raise :exc:`NotImplementedError` exception. Override this in subclasses to Raise a :exc:`NotImplementedError` exception. Override this in subclasses to
do something useful with this message. Whatever was passed in the do something useful with this message. Whatever was passed in the
constructor as *remoteaddr* will be available as the :attr:`_remoteaddr` constructor as *remoteaddr* will be available as the :attr:`_remoteaddr`
attribute. *peer* is the remote host's address, *mailfrom* is the envelope attribute. *peer* is the remote host's address, *mailfrom* is the envelope
originator, *rcpttos* are the envelope recipients and *data* is a string originator, *rcpttos* are the envelope recipients and *data* is a string
containing the contents of the e-mail (which should be in :rfc:`2822` containing the contents of the e-mail (which should be in :rfc:`5321`
format). format).
If the *decode_data* constructor keyword is set to ``True``, the *data* If the *decode_data* constructor keyword is set to ``True``, the *data*
argument will be a unicode string. If it is set to ``False``, it argument will be a unicode string. If it is set to ``False``, it
will be a bytes object. will be a bytes object.
Return ``None`` to request a normal ``250 Ok`` response; otherwise
return the desired response string in :RFC:`5321` format.
.. method:: process_smtputf8_message(peer, mailfrom, rcpttos, data)
Raise a :exc:`NotImplementedError` exception. Override this in
subclasses to do something useful with messages when *enable_SMTPUTF8*
has been set to ``True`` and the SMTP client requested ``SMTPUTF8``,
since this method is called rather than :meth:`process_message` when the
client actively requests ``SMTPUTF8``. The *data* argument will always
be a bytes object, and any non-``None`` return value should conform to
:rfc:`6531`; otherwise, the API is the same as for
:meth:`process_message`.
.. attribute:: channel_class .. attribute:: channel_class
Override this in subclasses to use a custom :class:`SMTPChannel` for Override this in subclasses to use a custom :class:`SMTPChannel` for
...@@ -68,8 +89,12 @@ SMTPServer Objects ...@@ -68,8 +89,12 @@ SMTPServer Objects
.. versionchanged:: 3.4 .. versionchanged:: 3.4
The *map* argument was added. The *map* argument was added.
.. versionchanged:: 3.5 the *decode_data* argument was added, and *localaddr* .. versionchanged:: 3.5
and *remoteaddr* may now contain IPv6 addresses. *localaddr* and *remoteaddr* may now contain IPv6 addresses.
.. versionadded:: 3.5
the *decode_data* and *enable_SMTPUTF8* constructor arguments, and the
:meth:`process_smtputf8_message` method.
DebuggingServer Objects DebuggingServer Objects
...@@ -109,7 +134,7 @@ SMTPChannel Objects ...@@ -109,7 +134,7 @@ SMTPChannel Objects
------------------- -------------------
.. class:: SMTPChannel(server, conn, addr, data_size_limit=33554432,\ .. class:: SMTPChannel(server, conn, addr, data_size_limit=33554432,\
map=None, decode_data=True) map=None, enable_SMTPUTF8=False, decode_data=True)
Create a new :class:`SMTPChannel` object which manages the communication Create a new :class:`SMTPChannel` object which manages the communication
between the server and a single SMTP client. between the server and a single SMTP client.
...@@ -120,6 +145,11 @@ SMTPChannel Objects ...@@ -120,6 +145,11 @@ SMTPChannel Objects
accepted in a ``DATA`` command. A value of ``None`` or ``0`` means no accepted in a ``DATA`` command. A value of ``None`` or ``0`` means no
limit. limit.
*enable_SMTPUTF8* determins whether the ``SMTPUTF8`` extension (as defined
in :RFC:`6531`) should be enabled. The default is ``False``. A
:exc:`ValueError` is raised if both *enable_SMTPUTF8* and *decode_data* are
set to ``True`` at the same time.
A dictionary can be specified in *map* to avoid using a global socket map. A dictionary can be specified in *map* to avoid using a global socket map.
*decode_data* specifies whether the data portion of the SMTP transaction *decode_data* specifies whether the data portion of the SMTP transaction
...@@ -131,7 +161,7 @@ SMTPChannel Objects ...@@ -131,7 +161,7 @@ SMTPChannel Objects
:attr:`SMTPServer.channel_class` of your :class:`SMTPServer`. :attr:`SMTPServer.channel_class` of your :class:`SMTPServer`.
.. versionchanged:: 3.5 .. versionchanged:: 3.5
the *decode_data* argument was added. the *decode_data* and *enable_SMTPUTF8* arguments were added.
The :class:`SMTPChannel` has the following instance variables: The :class:`SMTPChannel` has the following instance variables:
......
...@@ -218,6 +218,10 @@ smtpd ...@@ -218,6 +218,10 @@ smtpd
addresses in the :class:`~smtpd.SMTPServer` constructor, and have it addresses in the :class:`~smtpd.SMTPServer` constructor, and have it
successfully connect. (Contributed by Milan Oberkirch in :issue:`14758`.) successfully connect. (Contributed by Milan Oberkirch in :issue:`14758`.)
* :mod:`~smtpd.SMTPServer` now supports :rfc:`6531` via the *enable_SMTPUTF8*
constructor argument and a user-provided
:meth:`~smtpd.SMTPServer.process_smtputf8_message` method.
smtplib smtplib
------- -------
......
This diff is collapsed.
...@@ -102,7 +102,7 @@ class MockSocket: ...@@ -102,7 +102,7 @@ class MockSocket:
return len(data) return len(data)
def getpeername(self): def getpeername(self):
return 'peer' return ('peer-address', 'peer-port')
def close(self): def close(self):
pass pass
......
This diff is collapsed.
...@@ -115,6 +115,8 @@ Core and Builtins ...@@ -115,6 +115,8 @@ Core and Builtins
Library Library
------- -------
- Issue #21725: Added support for RFC 6531 (SMTPUTF8) in smtpd.
- Issue #22176: Update the ctypes module's libffi to v3.1. This release - Issue #22176: Update the ctypes module's libffi to v3.1. This release
adds support for the Linux AArch64 and POWERPC ELF ABIv2 little endian adds support for the Linux AArch64 and POWERPC ELF ABIv2 little endian
architectures. architectures.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment