7

I am EE, trying to write a script to simplify file checks using Python.

For some reason, our IT will not let me gain access to our SMTP server, and will only allow sending mail via mailx. So I've thought of running mailx from Python and send it, in the same way that it works in my console. Alas, it gives an exception. See Linux log below:

Python 3.1.1 (r311:74480, Dec  8 2009, 22:48:08) 
[GCC 3.3.3 (SuSE Linux)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import subprocess
>>> process=subprocess.Popen('echo "This is a test\nHave a loook see\n" | mailx -s "Test Python" mymail@mycomopany.com')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/depot/Python-3.1.1/lib/python3.1/subprocess.py", line 646, in __init__
    errread, errwrite)
  File "/depot/Python-3.1.1/lib/python3.1/subprocess.py", line 1146, in _execute_child
    raise child_exception

I am a newbie to Python (now migrating from Perl). Any thoughts?

tripleee
  • 175,061
  • 34
  • 275
  • 318
Lior Dagan
  • 71
  • 1
  • 1
  • 2

3 Answers3

10

you can use smtplib

import smtplib
# email options
SERVER = "localhost"
FROM = "root@example.com"
TO = ["root"]
SUBJECT = "Alert!"
TEXT = "This message was sent with Python's smtplib."


message = """\
From: %s
To: %s
Subject: %s

%s
""" % (FROM, ", ".join(TO), SUBJECT, TEXT)

server = smtplib.SMTP(SERVER)
server.set_debuglevel(3)
server.sendmail(FROM, TO, message)
server.quit()

If you really want to use subprocess( which i advise against)

import subprocess
import sys
cmd="""echo "test" | mailx -s 'test!' root"""
p=subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
output, errors = p.communicate()
print errors,output
ghostdog74
  • 327,991
  • 56
  • 259
  • 343
  • Manually assembling an email message with simple string pasting is error-prone and scales poorly. `mailx` takes care of some things behind the scenes for you which you probably want Python to handle on your behalf as well; basically, create an `email.message.EmailMessage` and use its API to set the headers and body, etc. (Older versions of Python had `email.message.Message` but this is obsolescent since 3.6 and should generally be avoided in new code.) – tripleee Jan 26 '21 at 14:26
  • For the `subprocess` solution, you should generally avoid `subprocess.Popen()` when `subprocess.run()` and friends (`subprocess.check_call()` etc) can take care of the job for you; this is definitely one of those situations. Also, you really would like to [avoid `shell=True`](https://stackoverflow.com/questions/3172470/actual-meaning-of-shell-true-in-subprocess) here. – tripleee Jan 26 '21 at 14:30
  • I also need to send email via python script on linux server using mailx and also need to attach csv file, any help would be appreciated – viki Dec 07 '21 at 00:56
1

You cas use subprocess.call. Like:

subprocess.call(["mailx", "-s", "\"Test Python\"", "mymail@mycomopany.com"])

Details here

F0RR
  • 1,590
  • 4
  • 16
  • 30
  • how I appreciate the brevity – galets May 09 '15 at 21:50
  • 1
    Why would you want to put literal double quotes around the subject header though? This will still get hung up on trying to read an email message from standard input. – tripleee Jan 26 '21 at 14:27
1

Lior Dagan's code was close to being correct/functional: the error in this approach is a missing shell=True kwarg in the call to subprocess.Popen. Anyone actually considering this approach should be aware that the subprocess documentation warns that:

Invoking the system shell with shell=True can be a security hazard if combined with untrusted input.

Generally F0RR's and ghostdog74's solutions should be preferred as they are more robust and secure.