To send e-mail using the Python SMTP module you need to somehow obtain the name of a valid mail exchanger (MX). That's either a local hub or smart relay of your own or you can query DNS for the public MX records for each target host/domain name.
This requirement is glossed over in the docs. It's a horrible omission in Python's standard libraries is that they don't provide an easy way to query DNS for an MX record. (There are rather nice third party Python DNS libraries such as DNSPython and PyDNS with extensive support for way more DNS than you need for anything related to e-mail).
In general you're probably better off using a list of hubs or relays from your own network (or ISP). This is because your efforts to send mail directly to the published MX hosts may otherwise run afoul of various attempts to fight spam. (For example it frequently won't be possible from wireless networks in coffee shops, hotels, and across common household cable and DSL connections; most of those address ranges are listed in various databases as potential sorts of spam). In that case you could store and/or retrieve the names/address of your local mail hubs (or smart relays) through any means you like. It could be a .cfg file (ConfigParser), or through an LDAP or SQL query or even (gasp!) hard-coded into your scripts.
If, however, your code is intended to run on a suitable network (for example in a colo, or a data center) then you'll have to do your own MX resolution. You could install one of the aforementioned PyPI packages. If you need to limit yourself to the standard libraries then you might be able to rely on the commonly available dig
utility that's included with most installations of Linux, MacOS X, Solaris, FreeBSD and other fine operating systems.
In that case you'd call a command like dig +short aol.com mx | awk '{print $NF}'
through subprocess.Popen()
which can be done with this rather ugly one-liner:
mxers = subprocess.Popen("dig +short %s mx | awk '{print $NF}'"
% target_domain, stdout=subprocess.PIPE,
shell=True).communicate()[0].split()
Then you can attempt to make an SMTP connection to each of the resulting hostnames in
turn. (This is fine so long as your "target_domain" value is adequately sanitized; don't pass untrusted data through Popen()
with shell=True
).
The safer version looks even hairier:
mxers = subprocess.Popen(["dig", "+short", target_domain, "mx"],
stdout=subprocess.PIPE).communicate()[0].split()[1::2]
... where the slice/stride at the end is replacing the call to awk
and thus obviating
the need for shell=True