Sunday, 4 March 2012

Send mail with attachment - python script

I've needed a shell script to daily send a log of some cron job. So after some googlin' and mixing some examples I got this :

#!/usr/bin/env python
# -*- coding: utf_8 -*-

import sys
from os import path
from smtplib import SMTP
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.MIMEBase import MIMEBase
from email import Encoders

fromad = "UserName@gmail.com"
toaddr = "AdminLogin@gmail.com"

msg = MIMEMultipart('mixed')
msg['Subject'] = sys.argv[1]
msg['From'] = fromad
msg['To'] = toaddr

text = "Some text that says details are in attached log or something"
body = MIMEText(text, 'plain')
msg.attach(body)

part = MIMEBase('application', "octet-stream")
fp = open(sys.argv[2], 'rb')
part.set_payload( fp.read() )
fp.close()
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"' % path.basename(sys.argv[2]))
msg.attach(part)

sndm = SMTP()
sndm.set_debuglevel(0)
sndm.connect('smtp.gmail.com', '587')
sndm.starttls()
#sndm.ehlo()
try :
    #sndm.esmtp_features['auth'] = 'LOGIN DIGEST-MD5 PLAIN'
    sndm.esmtp_features['auth'] = 'LOGIN'
    sndm.login('UserName', 'PassWord')
    sndm.sendmail(fromad, toaddr, msg.as_string())
    sndm.quit()
except Exception, e:
    print e

Usage : ./script.sh "Some email subject" /tmp/cron.log

Works great on openSuse 12.1, on Arch Linux 2011 - not so much - have to change 1st line to :
#!/usr/bin/python2

To use SSL instead of StartTLS switch to SMTP_SSL and change to proper port - for gmail SSL it's 465

from smtplib import SMTP_SSL
#from smtplib import SMTP
.
.
sndm = SMTP_SSL()
#sndm = SMTP()
.
.
sndm.connect('smtp.gmail.com', '465')
#sndm.connect('smtp.gmail.com', '587')
.
.
#sndm.starttls()

On Arch Linux 2011 line
#!/usr/bin/env python
runs script under Python 3.2, not 2.7.

Here's a working version for Python 3.2 on Arch Linux.
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
from os import path
from smtplib import SMTP_SSL
#from smtplib import SMTP
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders

fromad = "UserName@gmail.com"
toaddr = "AdminLogin@gmail.com"

msg = MIMEMultipart('mixed')
msg['Subject'] = sys.argv[1]
msg['From'] = fromad
msg['To'] = toaddr

text = "Some text that says details are in attached log or something"
body = MIMEText(text, 'plain', 'utf-8')
msg.attach(body)

part = MIMEBase('application', "octet-stream")
fp = open(sys.argv[2], 'rb')
part.set_payload( fp.read() )
fp.close()
encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"' % path.basename(sys.argv[2]))
msg.attach(part)

sndm = SMTP_SSL()
#sndm = SMTP()
sndm.set_debuglevel(1)
sndm.connect('smtp.gmail.com', '465')
#sndm.starttls()
#sndm.ehlo()
try :
    #sndm.esmtp_features['auth'] = 'LOGIN DIGEST-MD5 PLAIN'
    sndm.esmtp_features['auth'] = 'LOGIN'
    sndm.login('UserName', 'PassWord')
    sndm.sendmail(fromad, toaddr, msg.as_string())
    sndm.quit()
except Exception as e:
    print(e)

Biggest problem I found with Python 3.2 version is you can't use non-ascii letters for email subject - if you do script will stop with something like this
'ascii' codec can't decode byte 0xc4 in position 0: ordinal not in range(128)

To check which auth methods servers support you can either use
telnet plus.smtp.mail.yahoo.com 25
ehlo me
quit
or for SSL
openssl s_client -connect smtp.zoho.com:465
ehlo me
Q  -to quit connection

2 comments:

  1. Thanks for sharing. I tried a few other solutions but this is the only one that worked for me.

    ReplyDelete
  2. The mail should be coded in utf-8 to avoid weird characters. Is not that trivial.

    ReplyDelete