python aiosmtpd server with basic authentication

1.7k Views Asked by At

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?
1

There are 1 best solutions below

5
pepoluan On BEST ANSWER

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
    )