Clean up the mta directory.
[mailman.git] / src / mailman / mta / connection.py
blob44cc31d862adf8d32203ffefa09629291db9760c
1 # Copyright (C) 2009-2016 by the Free Software Foundation, Inc.
3 # This file is part of GNU Mailman.
5 # GNU Mailman is free software: you can redistribute it and/or modify it under
6 # the terms of the GNU General Public License as published by the Free
7 # Software Foundation, either version 3 of the License, or (at your option)
8 # any later version.
10 # GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 # more details.
15 # You should have received a copy of the GNU General Public License along with
16 # GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
18 """MTA connections."""
20 import logging
21 import smtplib
23 from contextlib import suppress
24 from lazr.config import as_boolean
25 from mailman import public
26 from mailman.config import config
29 log = logging.getLogger('mailman.smtp')
32 @public
33 class Connection:
34 """Manage a connection to the SMTP server."""
35 def __init__(self, host, port, sessions_per_connection,
36 smtp_user=None, smtp_pass=None):
37 """Create a connection manager.
39 :param host: The host name of the SMTP server to connect to.
40 :type host: string
41 :param port: The port number of the SMTP server to connect to.
42 :type port: integer
43 :param sessions_per_connection: The number of SMTP sessions per
44 connection to the SMTP server. After this number of sessions
45 has been reached, the connection is closed and a new one is
46 opened. Set to zero for an unlimited number of sessions per
47 connection (i.e. your MTA has no limit).
48 :type sessions_per_connection: integer
49 :param smtp_user: Optional SMTP authentication user name. If given,
50 `smtp_pass` must also be given.
51 :type smtp_user: str
52 :param smtp_pass: Optional SMTP authentication password. If given,
53 `smtp_user` must also be given.
54 """
55 self._host = host
56 self._port = port
57 self._sessions_per_connection = sessions_per_connection
58 self._username = smtp_user
59 self._password = smtp_pass
60 self._session_count = None
61 self._connection = None
63 def _connect(self):
64 """Open a new connection."""
65 self._connection = smtplib.SMTP()
66 log.debug('Connecting to %s:%s', self._host, self._port)
67 self._connection.connect(self._host, self._port)
68 if self._username is not None and self._password is not None:
69 log.debug('Logging in')
70 self._connection.login(self._username, self._password)
71 self._session_count = self._sessions_per_connection
73 def sendmail(self, envsender, recipients, msgtext):
74 """Mimic `smtplib.SMTP.sendmail`."""
75 if as_boolean(config.devmode.enabled):
76 # Force the recipients to the specified address, but still deliver
77 # to the same number of recipients.
78 recipients = [config.devmode.recipient] * len(recipients)
79 if self._connection is None:
80 self._connect()
81 try:
82 log.debug('envsender: %s, recipients: %s, size(msgtext): %s',
83 envsender, recipients, len(msgtext))
84 results = self._connection.sendmail(envsender, recipients, msgtext)
85 except smtplib.SMTPException:
86 # For safety, close this connection. The next send attempt will
87 # automatically re-open it. Pass the exception on up.
88 self.quit()
89 raise
90 # This session has been successfully completed.
91 self._session_count -= 1
92 # By testing exactly for equality to 0, we automatically handle the
93 # case for SMTP_MAX_SESSIONS_PER_CONNECTION <= 0 meaning never close
94 # the connection. We won't worry about wraparound <wink>.
95 if self._session_count == 0:
96 self.quit()
97 return results
99 def quit(self):
100 """Mimic `smtplib.SMTP.quit`."""
101 if self._connection is None:
102 return
103 with suppress(smtplib.SMTPException):
104 self._connection.quit()
105 self._connection = None