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

Missing multiple RFC support (MAIL FROM + RCPT TO) #367

Open
perexg opened this issue Jan 28, 2023 · 3 comments
Open

Missing multiple RFC support (MAIL FROM + RCPT TO) #367

perexg opened this issue Jan 28, 2023 · 3 comments

Comments

@perexg
Copy link

perexg commented Jan 28, 2023

I'm using this diff in my local smtp server which works as a proxy for the postfix. The aiosmtpd does not understand some parameters for MAIL FROM and RCPT TO:

diff --git a/aiosmtpd/smtp.py b/aiosmtpd/smtp.py
index a977f75..300bfee 100644
--- a/aiosmtpd/smtp.py
+++ b/aiosmtpd/smtp.py
@@ -1281,6 +1281,9 @@ class SMTP(asyncio.StreamReaderProtocol):
                     '552 Error: message size exceeds fixed maximum message '
                     'size')
                 return
+        envid = params.pop('ENVID', None)  # RFC 3885
+        auth = params.pop('AUTH', None) # RFC 4954
+        ret = params.pop('RET', None)  # RFC 3461
         if len(params) > 0:
             await self.push(
                 '555 MAIL FROM parameters not recognized or not implemented')
@@ -1322,6 +1325,8 @@ class SMTP(asyncio.StreamReaderProtocol):
         if params is None:
             return await self.push(syntaxerr)
         # XXX currently there are no options we recognize.
+        orcpt = params.pop("ORCPT", None) # RFC 1891
+        notify = params.pop("NOTIFY", None) # RFC 3461
         if len(params) > 0:
             return await self.push(
                 '555 RCPT TO parameters not recognized or not implemented'

It would be nice, if someone can add those extensions. Also, it may be nice to have a list of parameters to be skipped in the SMTP class, so users can add the extra parameters to the class (using own class or assignments) without the need to modify directly the base class.

EDIT: v2 - added NOTIFY parameter

@nim-odoo
Copy link

If I understand correctly https://www.rfc-editor.org/rfc/rfc4954#section-5

For this reason, servers that advertise support for this
extension MUST support the AUTH parameter to the MAIL FROM
command even when the client has not authenticated itself to the
server.

Since aiosmtpd advertises AUTH LOGIN PLAIN by default, it should not reject mails using AUTH in their MAIL FROM.

@nim-odoo
Copy link

nim-odoo commented Feb 13, 2023

Still early, but it seems the following fixes the issue related to AUTH=<> (which is the most common):

    async def handle_EHLO(self, server, session, envelope, hostname, response):
        """
        EHLO handler intended to remove the '250-AUTH' line from the response since we do not use
        any authentication.
        """

        session.host_name = hostname
        return [r for r in response if not r.startswith("250-AUTH")]

But of course it only works if clients properly implement the RFC.

@perexg
Copy link
Author

perexg commented Feb 14, 2023

I though about something like this (to allow override the SMTP class methods):

diff --git a/aiosmtpd/smtp.py b/aiosmtpd/smtp.py
index a977f75..41bdf70 100644
--- a/aiosmtpd/smtp.py
+++ b/aiosmtpd/smtp.py
@@ -1225,6 +1225,10 @@ class SMTP(asyncio.StreamReaderProtocol):
         else:
             await self.push('501 Syntax: VRFY <address>')
 
+    def mail_cmd_params(self, params):
+        """Handle extra parameters for MAIL smtp command"""
+        return
+
     @syntax('MAIL FROM: <address>', extended=' [SP <mail-parameters>]')
     async def smtp_MAIL(self, arg: str) -> None:
         if await self.check_helo_needed():
@@ -1281,7 +1285,8 @@ class SMTP(asyncio.StreamReaderProtocol):
                     '552 Error: message size exceeds fixed maximum message '
                     'size')
                 return
-        if len(params) > 0:
+        r = self.mail_cmd_params(params)
+        if r or len(params) > 0:
             await self.push(
                 '555 MAIL FROM parameters not recognized or not implemented')
             return
@@ -1293,6 +1298,10 @@ class SMTP(asyncio.StreamReaderProtocol):
         log.info('%r sender: %s', self.session.peer, address)
         await self.push(status)
 
+    def rcpt_cmd_params(self, params):
+        """Handle extra parameters for RCPT smtp command"""
+        return
+
     @syntax('RCPT TO: <address>', extended=' [SP <mail-parameters>]')
     async def smtp_RCPT(self, arg: str) -> None:
         if await self.check_helo_needed():
@@ -1321,8 +1330,8 @@ class SMTP(asyncio.StreamReaderProtocol):
         params = self._getparams(rcpt_options)
         if params is None:
             return await self.push(syntaxerr)
-        # XXX currently there are no options we recognize.
-        if len(params) > 0:
+        r = self.rcpt_cmd_params(params)
+        if r or len(params) > 0:
             return await self.push(
                 '555 RCPT TO parameters not recognized or not implemented'
             )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants