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.