MTA connections

Outgoing connections to the outgoing mail transport agent (MTA) are mitigated through a Connection class, which can transparently manage multiple sessions in a single connection.

>>> from mailman.mta.connection import Connection

The number of sessions per connections is specified when the Connection object is created, as is the host and port number of the SMTP server. Zero means there’s an unlimited number of sessions per connection.

>>> connection = Connection(
...     config.mta.smtp_host, int(config.mta.smtp_port), 0)

At the start, there have been no connections to the server.

>>> smtpd.get_connection_count()
0

By sending a message to the server, a connection is opened.

>>> connection.sendmail('anne@example.com', ['bart@example.com'], """\
... From: anne@example.com
... To: bart@example.com
... Subject: aardvarks
...
... """)
{}

>>> smtpd.get_connection_count()
1

We can reset the connection count back to zero.

>>> from smtplib import SMTP
>>> def reset():
...     smtpd = SMTP()
...     smtpd.connect(config.mta.smtp_host, int(config.mta.smtp_port))
...     smtpd.docmd('RSET')

>>> reset()
>>> smtpd.get_connection_count()
0

>>> connection.quit()

By providing an SMTP user name and password in the configuration file, Mailman will authenticate with the mail server after each new connection.

>>> config.push('auth', """
... [mta]
... smtp_user: testuser
... smtp_pass: testpass
... """)

>>> connection = Connection(
...     config.mta.smtp_host, int(config.mta.smtp_port), 0,
...     config.mta.smtp_user, config.mta.smtp_pass)
>>> connection.sendmail('anne@example.com', ['bart@example.com'], """\
... From: anne@example.com
... To: bart@example.com
... Subject: aardvarks
...
... """)
{}
>>> print(smtpd.get_authentication_credentials())
PLAIN AHRlc3R1c2VyAHRlc3RwYXNz

>>> reset()
>>> config.pop('auth')

Sessions per connection

Let’s say we specify a maximum number of sessions per connection of 2. When the third message is sent, the connection is torn down and a new one is created.

The connection count starts at zero.

>>> connection = Connection(
...     config.mta.smtp_host, int(config.mta.smtp_port), 2)

>>> smtpd.get_connection_count()
0

We send two messages through the Connection object. Only one connection is opened.

>>> connection.sendmail('anne@example.com', ['bart@example.com'], """\
... From: anne@example.com
... To: bart@example.com
... Subject: aardvarks
...
... """)
{}

>>> smtpd.get_connection_count()
1

>>> connection.sendmail('anne@example.com', ['bart@example.com'], """\
... From: anne@example.com
... To: bart@example.com
... Subject: aardvarks
...
... """)
{}

>>> smtpd.get_connection_count()
1

The third message would cause a third session, exceeding the maximum. So the current connection is closed and a new one opened.

>>> connection.sendmail('anne@example.com', ['bart@example.com'], """\
... From: anne@example.com
... To: bart@example.com
... Subject: aardvarks
...
... """)
{}

>>> smtpd.get_connection_count()
2

A fourth message does not cause a new connection to be made.

>>> connection.sendmail('anne@example.com', ['bart@example.com'], """\
... From: anne@example.com
... To: bart@example.com
... Subject: aardvarks
...
... """)
{}

>>> smtpd.get_connection_count()
2

But a fifth one does.

>>> connection.sendmail('anne@example.com', ['bart@example.com'], """\
... From: anne@example.com
... To: bart@example.com
... Subject: aardvarks
...
... """)
{}

>>> smtpd.get_connection_count()
3

No maximum

A value of zero means that there is an unlimited number of sessions per connection.

>>> connection = Connection(
...     config.mta.smtp_host, int(config.mta.smtp_port), 0)
>>> reset()

Even after ten messages are sent, there’s still been only one connection to the server.

>>> connection.debug = True
>>> for i in range(10):
...     # Ignore the results.
...     results = connection.sendmail(
...         'anne@example.com', ['bart@example.com'], """\
... From: anne@example.com
... To: bart@example.com
... Subject: aardvarks
...
... """)

>>> smtpd.get_connection_count()
1

Development mode

By putting Mailman into development mode, you can force the recipients to a given hard-coded address. This allows you to test Mailman without worrying about accidental deliveries to unintended recipients.

>>> config.push('devmode', """
... [devmode]
... enabled: yes
... recipient: zperson@example.com
... """)

>>> smtpd.clear()
>>> connection.sendmail(
...     'anne@example.com',
...     ['bart@example.com', 'cate@example.com'], """\
... From: anne@example.com
... To: bart@example.com
... Subject: aardvarks
...
... """)
{}

>>> messages = list(smtpd.messages)
>>> len(messages)
1
>>> print(messages[0].as_string())
From: anne@example.com
To: bart@example.com
Subject: aardvarks
X-Peer: ...
X-MailFrom: anne@example.com
X-RcptTo: zperson@example.com, zperson@example.com



>>> config.pop('devmode')