smtpd — SMTP Server

Source code:Lib/smtpd.py


This module offers several classes to implement SMTP (email) servers.

See also

Theaiosmtpd package is a recommendedreplacement for this module. It is based onasyncio and provides amore straightforward API.smtpd should be considered deprecated.

Several server implementations are present; one is a genericdo-nothing implementation, which can be overridden, while the other two offerspecific mail-sending strategies.

Additionally the SMTPChannel may be extended to implement very specificinteraction behaviour with SMTP clients.

The code supportsRFC 5321, plus theRFC 1870 SIZE andRFC 6531SMTPUTF8 extensions.

SMTPServer Objects

classsmtpd.SMTPServer(localaddr,remoteaddr,data_size_limit=33554432,map=None,enable_SMTPUTF8=False,decode_data=False)

Create a newSMTPServer object, which binds to local addresslocaladdr. It will treatremoteaddr as an upstream SMTP relayer. Bothlocaladdr andremoteaddr should be a(host, port)tuple. The object inherits fromasyncore.dispatcher, and so willinsert itself intoasyncore’s event loop on instantiation.

data_size_limit specifies the maximum number of bytes that will beaccepted in aDATA command. A value ofNone or0 means nolimit.

map is the socket map to use for connections (an initially emptydictionary is a suitable value). If not specified theasyncoreglobal socket map is used.

enable_SMTPUTF8 determines whether theSMTPUTF8 extension (as definedinRFC 6531) should be enabled. The default isFalse.WhenTrue,SMTPUTF8 is accepted as a parameter to theMAILcommand and when present is passed toprocess_message() in thekwargs['mail_options'] list.decode_data andenable_SMTPUTF8cannot be set toTrue at the same time.

decode_data specifies whether the data portion of the SMTP transactionshould be decoded using UTF-8. Whendecode_data isFalse (thedefault), the server advertises the8BITMIMEextension (RFC 6152), accepts theBODY=8BITMIME parameter totheMAIL command, and when present passes it toprocess_message()in thekwargs['mail_options'] list.decode_data andenable_SMTPUTF8cannot be set toTrue at the same time.

process_message(peer,mailfrom,rcpttos,data,**kwargs)

Raise aNotImplementedError exception. Override this in subclasses todo something useful with this message. Whatever was passed in theconstructor asremoteaddr will be available as the_remoteaddrattribute.peer is the remote host’s address,mailfrom is the envelopeoriginator,rcpttos are the envelope recipients anddata is a stringcontaining the contents of the e-mail (which should be inRFC 5321format).

If thedecode_data constructor keyword is set toTrue, thedataargument will be a unicode string. If it is set toFalse, itwill be a bytes object.

kwargs is a dictionary containing additional information. It is emptyifdecode_data=True was given as an init argument, otherwiseit contains the following keys:

mail_options:

a list of all received parameters to theMAILcommand (the elements are uppercase strings; example:['BODY=8BITMIME','SMTPUTF8']).

rcpt_options:

same asmail_options but for theRCPT command.Currently noRCPTTO options are supported, so for nowthis will always be an empty list.

Implementations ofprocess_message should use the**kwargssignature to accept arbitrary keyword arguments, since future featureenhancements may add keys to the kwargs dictionary.

ReturnNone to request a normal250Ok response; otherwisereturn the desired response string inRFC 5321 format.

channel_class

Override this in subclasses to use a customSMTPChannel formanaging SMTP clients.

New in version 3.4:Themap constructor argument.

Changed in version 3.5:localaddr andremoteaddr may now contain IPv6 addresses.

New in version 3.5:Thedecode_data andenable_SMTPUTF8 constructor parameters, and thekwargs parameter toprocess_message() whendecode_data isFalse.

Changed in version 3.6:decode_data is nowFalse by default.

DebuggingServer Objects

classsmtpd.DebuggingServer(localaddr,remoteaddr)

Create a new debugging server. Arguments are as perSMTPServer.Messages will be discarded, and printed on stdout.

PureProxy Objects

classsmtpd.PureProxy(localaddr,remoteaddr)

Create a new pure proxy server. Arguments are as perSMTPServer.Everything will be relayed toremoteaddr. Note that running this has a goodchance to make you into an open relay, so please be careful.

MailmanProxy Objects

classsmtpd.MailmanProxy(localaddr,remoteaddr)

Create a new pure proxy server. Arguments are as perSMTPServer.Everything will be relayed toremoteaddr, unless local mailman configurationsknows about an address, in which case it will be handled via mailman. Note thatrunning this has a good chance to make you into an open relay, so please becareful.

SMTPChannel Objects

classsmtpd.SMTPChannel(server,conn,addr,data_size_limit=33554432,map=None,enable_SMTPUTF8=False,decode_data=False)

Create a newSMTPChannel object which manages the communicationbetween the server and a single SMTP client.

conn andaddr are as per the instance variables described below.

data_size_limit specifies the maximum number of bytes that will beaccepted in aDATA command. A value ofNone or0 means nolimit.

enable_SMTPUTF8 determines whether theSMTPUTF8 extension (as definedinRFC 6531) should be enabled. The default isFalse.decode_data andenable_SMTPUTF8 cannot be set toTrue at the sametime.

A dictionary can be specified inmap to avoid using a global socket map.

decode_data specifies whether the data portion of the SMTP transactionshould be decoded using UTF-8. The default isFalse.decode_data andenable_SMTPUTF8 cannot be set toTrue at the sametime.

To use a custom SMTPChannel implementation you need to override theSMTPServer.channel_class of yourSMTPServer.

Changed in version 3.5:Thedecode_data andenable_SMTPUTF8 parameters were added.

Changed in version 3.6:decode_data is nowFalse by default.

TheSMTPChannel has the following instance variables:

smtp_server

Holds theSMTPServer that spawned this channel.

conn

Holds the socket object connecting to the client.

addr

Holds the address of the client, the second value returned bysocket.accept

received_lines

Holds a list of the line strings (decoded using UTF-8) received fromthe client. The lines have their"\r\n" line ending translated to"\n".

smtp_state

Holds the current state of the channel. This will be eitherCOMMAND initially and thenDATA after the client sendsa “DATA” line.

seen_greeting

Holds a string containing the greeting sent by the client in its “HELO”.

mailfrom

Holds a string containing the address identified in the “MAIL FROM:” linefrom the client.

rcpttos

Holds a list of strings containing the addresses identified in the“RCPT TO:” lines from the client.

received_data

Holds a string containing all of the data sent by the client during theDATA state, up to but not including the terminating"\r\n.\r\n".

fqdn

Holds the fully-qualified domain name of the server as returned bysocket.getfqdn().

peer

Holds the name of the client peer as returned byconn.getpeername()whereconn isconn.

TheSMTPChannel operates by invoking methods namedsmtp_<command>upon reception of a command line from the client. Built into the baseSMTPChannel class are methods for handling the following commands(and responding to them appropriately):

Command

Action taken

HELO

Accepts the greeting from the client and stores it inseen_greeting. Sets server to base command mode.

EHLO

Accepts the greeting from the client and stores it inseen_greeting. Sets server to extended command mode.

NOOP

Takes no action.

QUIT

Closes the connection cleanly.

MAIL

Accepts the “MAIL FROM:” syntax and stores the supplied address asmailfrom. In extended command mode, accepts theRFC 1870 SIZE attribute and responds appropriately based on thevalue ofdata_size_limit.

RCPT

Accepts the “RCPT TO:” syntax and stores the supplied addresses inthercpttos list.

RSET

Resets themailfrom,rcpttos, andreceived_data, but not the greeting.

DATA

Sets the internal state toDATA and stores remaining linesfrom the client inreceived_data until the terminator"\r\n.\r\n" is received.

HELP

Returns minimal information on command syntax

VRFY

Returns code 252 (the server doesn’t know if the address is valid)

EXPN

Reports that the command is not implemented.