Sending an email with python

purpleflame

New Member
Messages
17
Reaction score
0
Points
0
I am interested in making a cron job that will send email. So to start off with I am making a script to send an email with a python script. I found a couple different ways to do this -- using sendmail and smtplib. I tried using the sendmail method with this script but I do not know where it went wrong.
Code:
# This script is to test using the sendmail pipe to send emails.

#!/usr/bin/env python

print "Content-type: text/plain"
print

import os

MAIL = "/usr/sbin/sendmail"

# Read the email message from a file.
f = open('sampleemail.txt', 'r')
mssg = f.read()
f.close()

# Open a pipe to the mail program and write the data to the pipe.
p = os.popen("%s -t" % MAIL, 'w')
p.write(mssg)
exitcode = p.close()
if exitcode:
    print "Exit code: %s" % exitcode
I get an Internal Server Error 500. When I look at my error logs the only new listing is:
Code:
[Mon Apr 06 19:46:53 2009] [error] [client 141.217.222.214] File does not exist: /home/pf/public_html/500.shtml
What is odd is that I also made one to test sending with smtplib. This script does the same thing but also sends the email. Odd fo_O
Code:
#!/usr/bin/env python

import smtplib

SERVER = "localhost"

FROM = "purple@purpleflame.exofire.net"
TO = ["alikakakhel@yahoo.com"] # must be a list

SUBJECT = "Testing..."

TEXT = "...working"

# Prepare actual message

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

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

# Send the mail

server = smtplib.SMTP(SERVER)
server.sendmail(FROM, TO, message)
server.quit()
Any ideas?
 

garrettroyce

Community Support
Community Support
Messages
5,609
Reaction score
250
Points
63
Isn't it "/usr/bin/sendmail" and not " "/usr/sbin/sendmail"
 

purpleflame

New Member
Messages
17
Reaction score
0
Points
0
I thought of that possibility, but my cpanel tells me its what I put. Hence my putting it. I am on the absolut server if that helps. I tried changing it to what you wrote and trying anyway, but only had the same thing happen.

Any idea the other script sends the mail, but also gives the error?
 

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
Tests say /usr/sbin/sendmail is the winner.

The path to sampleemail.txt is probably wrong, unless you put it in cgi-bin/.

Always test for exceptions. Wrap a
Code:
try:
    ...
except Exception, exc:
    print exc
block around your code & see if you catch anything.
 

purpleflame

New Member
Messages
17
Reaction score
0
Points
0
My file sampleemail.txt is in the same folder as the script. The script has permissions 755. Is that not enough? Also I have it set so that python scripts can run in the folder the script is in.

I tried putting the try structure in but I get the same thing. This time the error logs show this instead.

Code:
[Tue Apr 07 09:16:20 2009] [error] [client 141.217.222.214] File does not exist: /home/pf/public_html/favicon.ico
[Tue Apr 07 09:16:18 2009] [error] [client 141.217.222.214] File does not exist: /home/pf/public_html/favicon.ico
[Tue Apr 07 09:16:17 2009] [error] [client 141.217.222.214] File does not exist: /home/pf/public_html/500.shtml
 

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
My file sampleemail.txt is in the same folder as the script.

You might want to move it. I don't think it will create a security hole to leave it there, but cgi-bin is not meant for storing data.

The script has permissions 755. Is that not enough? Also I have it set so that python scripts can run in the folder the script is in.

I tried putting the try structure in but I get the same thing.

Then you've got me stumped. I tested the following, which is basically your code plus the exception handler, and it worked for me:
Code:
#!/usr/bin/env python
print "Content-type: text/plain"
print

import os, datetime

MAIL="/usr/sbin/sendmail"

try:
    # Read the email message from a file.
    f = open('sampleemail.txt', 'r')
    mssg = f.read()
    f.close()
    mssg += datetime.datetime.now().__str__() + "\n"
    
    exitcode=1
    # Open a pipe to the mail program and write the data to the pipe.
    p = os.popen("%s -t" % MAIL, 'w')
    p.write(mssg)
    exitcode = p.close()
    if exitcode:
        print "Exit code: %s" % exitcode
    else:
        print "Mail sent"
except Exception, exc:
    print exc


Wait a minute: is this the literal start to your script?
Code:
# This script is to test using the sendmail pipe to send emails.

#!/usr/bin/env python

If so, that's the problem. The shebang line must be the first line for the shell to know what executable to pass the script to. I had been assuming the comment was added when you posted the script.

Anyway, now you know to always catch exceptions. You should also look into using subprocess rather than os.popen.
 
Last edited:

Parsa44

New Member
Messages
232
Reaction score
0
Points
0
Why do it with python when you can do it with PHP, easier and simpler.
 

purpleflame

New Member
Messages
17
Reaction score
0
Points
0
Looks like the issue with not putting the shebang at the very beginning was the issue.

So now I am trying to use subprocess instead of os, but it tells me:
Code:
'file' object has no attribute 'communicate'
I went to the webpage you gave and tryed to replace the os usage with the subprocess usage.

Code:
#!/usr/bin/env python

# This script is to test using the sendmail pipe to send emails.

print "Content-type: text/plain"
print

import subprocess

try:
    # Path to sendmail
    MAIL = "/usr/sbin/sendmail"

    # Read the email message from a file.
    f = open('sampleemail.txt', 'r')
    mssg = f.read()
    f.close()
    
    # Open a pipe to the mail program and write the data to the pipe using the subprocess library.
    p = subprocess.Popen("%s -t" % MAIL, shell=True, bufsize=0, stdin=subprocess.PIPE).stdin
    p.communicate(mssg)
    exitcode = p.terminate()
    
    if exitcode:
            print "Exit code: %s" % exitcode
except Exception, exc:
    print exc
I am not sure why it is going to file and not sendmail since that is what MAIL has in it. Am I supposed to use send_signal rather than communicate?
 

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
So now I am trying to use subprocess instead of os, but it tells me:
Code:
'file' object has no attribute 'communicate'
[...]
I am not sure why it is going to file and not sendmail since that is what MAIL has in it. Am I supposed to use send_signal rather than communicate?

That's because in your code, you set "p" to the process's stdin, which makes it a file (note the error message tells you this), not the process (a Popen). You use the 'write' method on files, 'communicate' on Popen objects. If ever you're getting an "object has no attribute" error, it's probably because a variable doesn't hold what you think it holds.

Signals are a very basic IPC mechanism. You can only send 32 asynchronous messages (most with predefined meanings; older systems had fewer signals). If a process is handling a signal, it can't receive any more signals of the same type. Moreover, receiving a signal while handling another can cause problems (depending on how you've set up signal handling). In short, no, don't use send_signal.

Also, there's no need to pass arguments with default values to a function when you're using keyword arguments.

Try this:
Code:
#!/usr/bin/env python

print "Content-type: text/plain"
print

import os, subprocess, datetime

mailer = "/usr/sbin/sendmail"

def readmsg(fname='../sampleemail.txt'):
    msgfile = open(fname, 'r')
    msg = msgfile.read()
    msgfile.close()
    return msg + datetime.datetime.now().__str__() + "\n"

# Open a pipe to the mail program and write the data to the pipe.
def sendmail(msg):
    p=subprocess.Popen([mailer,"-t"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    p.stdin.write(msg)
    p.stdin.close();
    return (p.returncode, p.stdout.read())

try:
    print "Using", mailer
    # Read the email message from a file.
    msg = readmsg();
    print "Sending {\n", msg, "}"
    (returncode, rsltmsg) = sendmail(msg)
    if returncode:
        print "Sendmail failed with code", returncode
        if len(rsltmsg):
            print "Sendmail had this to say:", rsltmsg
except IOError, exc:
    print "Error creating message:", exc
except Exception, exc:
    print 'Error while mailing', exc

You'll want to refactor to get rid of the "mailer" global, either by creating a class or using closures (examples of closures).

Edit:
Don't forget to move sampleemail.txt & update the script.
 
Last edited:

hardbyte

New Member
Messages
6
Reaction score
0
Points
0
I had an issue with email sending from python also. The weird thing is it worked in the past. I think the server changed a few months ago and that somehow broke it. While writing this post I actually fixed my problem :p

Any how instead of using sendmail directly like you I used the python module "smtplib" which calls (hopefully) to any smtp listener.

Code:
import time

testing = True

import smtplib
print "imported smtplib" 

def mail(serverURL="localhost", sender='', to='', subject='', text=''): 
    """ 
    Usage: 
    mail('somemailserver.com', 'me@example.com', 'someone@example.com', 'test', 'This is a test') 
    """ 
    headers = "From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n" % (sender, to, subject) 
    message = headers + text 
    mailServer = smtplib.SMTP(serverURL) 
    mailServer.sendmail(sender, to, message) 
    mailServer.quit() 
 
     
def test(): 
    
    mailMe = ('localhost','noreply@example.com','example-user@example.com','Test send email','python email sending test')
    mail(*mailMe)
    print "Settings Used: ", mailMe
    
if testing:
    print "cron script is running test at " + time.ctime()
    test()
This seems to work so why bother with the touching the metal approach of using sendmail?


p.s what the hell is with the un-trusting nature of this forum? Passing a turing test to post or search what is wrong with just a login capta like every other site on the interweb...
Edit:
Why do it with python when you can do it with PHP, easier and simpler.
Because python is cleaner, more powerful and most importantly "cooler"... ;)

http://effbot.org/pyfaq/how-do-i-send-mail-from-a-python-script.htm was useful for me by the way. It mentions your method purpleflame.
 
Last edited:
Top