3

Im trying to create an aiosmtpd server to process emails received. It works great without authentication, yet i simply cannot figure out how to setup the authentication. I have gone through the documents and searched for examples on this.

a sample of how im currently using it:

from aiosmtpd.controller import Controller

class CustomHandler:
    async def handle_DATA(self, server, session, envelope):
        peer = session.peer
        mail_from = envelope.mail_from
        rcpt_tos = envelope.rcpt_tos
        data = envelope.content         # type: bytes
        # Process message data...
        print('peer:' + str(peer))
        print('mail_from:' + str(mail_from))
        print('rcpt_tos:' + str(rcpt_tos))
        print('data:' + str(data))
        return '250 OK'

if __name__ == '__main__':
    handler = CustomHandler()
    controller = Controller(handler, hostname='192.168.8.125', port=10025)
    # Run the event loop in a separate thread.
    controller.start()
    # Wait for the user to press Return.
    input('SMTP server running. Press Return to stop server and exit.')
    controller.stop()```

which is the basic method from the documentation.

could someone please provide me with an example as to how to do simple authentication?
paulnm
  • 33
  • 3

1 Answers1

4

Alright, since you're using version 1.3.0, you can follow the documentation for Authentication.

A quick way to start is to create an "authenticator function" (can be a method in your handler class, can be standalone) that follows the Authenticator Callback guidelines.

A simple example:

from aiosmtpd.smtp import AuthResult, LoginPassword

auth_db = {
    b"user1": b"password1",
    b"user2": b"password2",
    b"user3": b"password3",
}

# Name can actually be anything
def authenticator_func(server, session, envelope, mechanism, auth_data):
    # For this simple example, we'll ignore other parameters
    assert isinstance(auth_data, LoginPassword)
    username = auth_data.login
    password = auth_data.password
    # If we're using a set containing tuples of (username, password),
    # we can simply use `auth_data in auth_set`.
    # Or you can get fancy and use a full-fledged database to perform
    # a query :-)
    if auth_db.get(username) == password:
        return AuthResult(success=True)
    else:
        return AuthResult(success=False, handled=False)

Then you're creating the controller, create it like so:

    controller = Controller(
        handler,
        hostname='192.168.8.125',
        port=10025,
        authenticator=authenticator_func,  # i.e., the name of your authenticator function
        auth_required=True,  # Depending on your needs
    )
pepoluan
  • 6,132
  • 4
  • 46
  • 76
  • 1
    That is exactly what i was looking for. I would give it a go tonight, Thank you so much. – paulnm Feb 17 '21 at 13:37
  • This auth function doesn't work for me. When I try and access the SMTP server, not I get an error saying AUTH isn't supported by the server. – MattieG4 Nov 23 '21 at 16:28
  • 2
    @MattieG4 You're likely starting the controller without specifying a TLS context. In that case, you need to pass `auth_require_tls=False` to the SMTP constructor. If you're using the latest version, just add `auth_require_tls=False` as the last kwarg when calling `Controller()` – pepoluan Nov 24 '21 at 02:57
  • 1
    @MattieG4 If you think the server behaves unexpectedly, please check the server's logs. The latest version of aiosmtpd has quite extensive logging to help troubleshoot. By default it logs to syslog's `mail` facility. – pepoluan Nov 24 '21 at 02:58
  • Can the example be updated to include the extra parameter required? – MattieG4 Nov 24 '21 at 16:06