Relay Services¶
Relay services are given an existing message and attempt to delivery it to the message’s next destination. In a traditional MTA, this next destination will be looked up by the recipient’s domain MX record and delivery is done with SMTP. In other cases, such as when acting as an MDA, slimta is the final destination and delivery occurs locally with something like courier-maildrop.
In any case, the relay will report either its attempt was a success or whether failure was permanent or transient.
SMTP Smart-Host Relaying¶
A very common type of relaying is sending all mail through to a single destination. This could be a local mail server that delivers all mail to its ISP mail servers, or it could be useful for a “front-line” of email servers whose sole purpose is spam scanning before handing off for real processing and routing. This static delivery is generally called Smart-Hosting
Smart-Host relaying can be done with the
StaticSmtpRelay
class, which will maintain
a pool of connections to the destination that will be re-used if idle. For
example, to ensure no more than one open connection to a destination is open at
once:
from slimta.relay.smtp.static import StaticSmtpRelay
relay = StaticSmtpRelay('smarthost.example.com', pool_size=1)
SMTP MX Relaying¶
Email messages destined for a recipient address hosted elsewhere on the Internet are relayed by querying the recipient domain’s MX records. The result is a prioritized list of hostnames that should be considered the next hop for the message. The highest priority (given by the lowest MX preference number) hostname is tried first, and lower priority hostnames should be tried subsequently. MX relaying always uses port 25.
MX relaying can be done with the MxSmtpRelay
class, which will automatically cache MX records until their TTL and will
keep a StaticSmtpRelay
object for each
destination, so that connections are re-used:
from slimta.relay.smtp.mx import MxSmtpRelay
relay = MxSmtpRelay()
Recipient domains can be configured to ignore MX records and permanently
deliver to a certain hostname using the
force_mx()
method:
relay.force_mx('example.com', 'smarthost.example.com')
Changing Source IP¶
The source IP address of delivered mail is often hugely important, since one
wrong move and you may find your IP on one of hundreds of spam blacklists. With
more complex setups, an MTA will often have a pool of IP addresses to send
from. SMTP relays (StaticSmtpRelay
and
MxSmtpRelay
allow a constructor argument
socket_creator
that allows you to control socket bind address:
import random
source_ips = ['1.2.3.4', '1.3.5.7', '2.4.6.8']
def _socket_creator(address):
bind_ip = random.choice(source_ips)
return create_connection(address, source_address=(bind_ip, 0))
mx = MxSmtpRelay(socket_creator=_socket_creator)
In this example, every outbound relay attempt will call _socket_creator
before connecting, passing in the destination address
tuple (host and
port). The function should return an open and connected socket, ready for data.
Note
Because SMTP relay connections were designed to be pooled and recycled,
handling many Envelope
deliveries before disconnecting, the Envelope
objects are not passed in to the socket_creator
call. If you need access
to message data, such as recipients, your best option may be to create an
intermediate Relay
class that implements your logic and then calls
MxSmtpRelay.attempt
.
LMTP Relaying¶
The LMTP protocol is designed for delivering a message to its final destination. It’s greatest strength in this regard over SMTP is that it can report success or failure on a per-recipient basis.
LMTP relaying is available with the
StaticLmtpRelay
class, which is behaves very
similarly to static SMTP relaying:
from slimta.relay.smtp.static import StaticLmtpRelay
relay = StaticLmtpRelay()
HTTP Relaying¶
Similar to the HTTP Edge, HTTP can be used to relay messages
as the data payload of a request. The EHLO, sender, and recipients information
usually transferred in the SMTP request are sent as headers in the request.
Refer to the slimta.relay.http
module for more information on how this
request is constructed.
If the remote host is an HTTP Edge, the response to the
request will most likely have an X-Smtp-Reply
header that is used as the
message delivery Reply
when returning to the queue. If the response does not
have this header, then PermanentRelayError
is raised for
4XX
codes and TransientRelayError
is raised for
5XX
codes.
HTTP relays are set up by creating a HttpRelay
object:
from slimta.relay.http import HttpRelay
relay = HttpRelay('http://example.com:8025/messages/')
External Process Relaying¶
When slimta is configured to be the final destination for the email message,
it can stream a message to an external process to locally deliver the message.
This is how applications like courier-maildrop and dovecot-lda are given
messages. This method is modeled off the pipe daemon from postfix. This
type of relay is provided in the slimta.relay.pipe
module. Here’s an
example of delivery to the maildrop
command:
from slimta.relay.pipe import MaildropRelay
relay = MaildropRelay(timeout=10.0)
For more information, the Mail Delivery Agent tutorial and pipe
module documentation may be useful.