Sending mail via sendmail from python

Viewed 90322

If I want to send mail not via SMTP, but rather via sendmail, is there a library for python that encapsulates this process?

Better yet, is there a good library that abstracts the whole 'sendmail -versus- smtp' choice?

I'll be running this script on a bunch of unix hosts, only some of which are listening on localhost:25; a few of these are part of embedded systems and can't be set up to accept SMTP.

As part of Good Practice, I'd really like to have the library take care of header injection vulnerabilities itself -- so just dumping a string to popen('/usr/bin/sendmail', 'w') is a little closer to the metal than I'd like.

If the answer is 'go write a library,' so be it ;-)

8 Answers

Header injection isn't a factor in how you send the mail, it's a factor in how you construct the mail. Check the email package, construct the mail with that, serialise it, and send it to /usr/sbin/sendmail using the subprocess module:

import sys
from email.mime.text import MIMEText
from subprocess import Popen, PIPE


msg = MIMEText("Here is the body of my message")
msg["From"] = "me@example.com"
msg["To"] = "you@example.com"
msg["Subject"] = "This is the subject."
p = Popen(["/usr/sbin/sendmail", "-t", "-oi"], stdin=PIPE)
# Both Python 2.X and 3.X
p.communicate(msg.as_bytes() if sys.version_info >= (3,0) else msg.as_string()) 

# Python 2.X
p.communicate(msg.as_string())

# Python 3.X
p.communicate(msg.as_bytes())

This is a simple python function that uses the unix sendmail to deliver a mail.

def sendMail():
    sendmail_location = "/usr/sbin/sendmail" # sendmail location
    p = os.popen("%s -t" % sendmail_location, "w")
    p.write("From: %s\n" % "from@somewhere.com")
    p.write("To: %s\n" % "to@somewhereelse.com")
    p.write("Subject: thesubject\n")
    p.write("\n") # blank line separating headers from body
    p.write("body of the mail")
    status = p.close()
    if status != 0:
           print "Sendmail exit status", status

Python 3.5+ version:

import subprocess
from email.message import EmailMessage

def sendEmail(from_addr, to_addrs, msg_subject, msg_body):
    msg = EmailMessage()
    msg.set_content(msg_body)
    msg['From'] = from_addr
    msg['To'] = to_addrs
    msg['Subject'] = msg_subject

    sendmail_location = "/usr/sbin/sendmail"
    subprocess.run([sendmail_location, "-t", "-oi"], input=msg.as_bytes())

It's quite common to just use the sendmail command from Python using os.popen

Personally, for scripts i didn't write myself, I think just using the SMTP-protocol is better, since it wouldn't require installing say an sendmail clone to run on windows.

https://docs.python.org/library/smtplib.html

The easiest answer is the smtplib, you can find docs on it here.

All you need to do is configure your local sendmail to accept connection from localhost, which it probably already does by default. Sure, you're still using SMTP for the transfer, but it's the local sendmail, which is basically the same as using the commandline tool.

Related