#!/usr/bin/python ### ### A Python module containing various functions relating to ### electronic mail, such as sending it and processing it. ### ### Note that this was developed in 1999 and there are undoubtedly ### better ways of accomplishing email sending now. I'm just ### including it so that the code in MailmanLists.py which refers to ### it will work for you (if you choose to use it or try running it). ### ### Anthony R. Thompson, November 1999 ### Contact: put @ between art and sigilservices.com ### ### Copyright (C) 1998-2010 by the Free Software Foundation, Inc. ### ### This program is free software; you can redistribute it and/or ### modify it under the terms of the GNU General Public License ### as published by the Free Software Foundation; either version 2 ### of the License, or (at your option) any later version. ### ### This program is distributed in the hope that it will be useful, ### but WITHOUT ANY WARRANTY; without even the implied warranty of ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ### GNU General Public License for more details. ### ### You should have received a copy of the GNU General Public License ### along with this program; if not, write to the Free Software ### Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ### 02110-1301, USA. http://www.fsf.org/licensing/licenses/gpl.html ### import os, sys, string, re, smtplib class EMail: __instance = None # storage for the instance reference ### ### Implement singleton pattern; based on code found at: ### http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52558 ### def __init__(self): # Check whether we already have an instance if EMail.__instance is None: # Create and remember instance EMail.__instance = EMail.__impl() # Store instance reference as the only member in the handle self.__dict__['_EMail__instance'] = EMail.__instance def __getattr__(self, attr): return getattr(self.__instance, attr) def __setattr__(self, attr, value): return setattr(self.__instance, attr, value) class __impl: ### ### Initialize this class ### def __init__(self): self.smtpserver = 'localhost' # INSTALL self.admin = 'someadmin@somehost.org' # INSTALL; default From ### ### Send a message to someone via e-mail, separating multiple ### To addresses with a comma. Cc is supported by adding an ### other_header of "Cc: address@place.com", but Bcc is not ### supported. Use commas for multiple Ccs, as you'd expect. ### def send_mail(self,message,subject,toaddrs,fromaddr='',*other_headers): ### ### Set default From address, split To addresses into a list ### if fromaddr == '': fromaddr = self.admin toaddrs = re.sub(',\s+',',',toaddrs) tolist = string.splitfields(toaddrs, ',') ### ### Check for Cc field in other_headers; Bcc not supported ### because there is no way to make smtplib send it to ### someone but not show it in the mail headers (i.e., do ### an actual blind copy) ### ccaddrs = '' for eachheader in other_headers: if (re.search('Cc:',eachheader)): ccaddrs = eachheader[4:] break if (ccaddrs <> ''): ccaddrs = re.sub(', ',',',ccaddrs) for ccaddr in string.splitfields(ccaddrs, ','): tolist.append(ccaddr) ### ### Prepend headers to message and add separator; ### Date is added automatically by the SMTP server ### header = '' header = header + 'To: ' + toaddrs + "\n" header = header + 'From: ' + fromaddr + "\n" header = header + 'Subject: ' + subject + "\n" for eachheader in other_headers: header = header + eachheader + "\n" message = header + "\n" + message ### ### Actually send the mail, using the smtplib ### server = smtplib.SMTP(self.smtpserver) # Need to check for certain exception type; our old web # host was good because if you gave it a bad sender # (nonexistent@our.org), it would raise SMTPSenderRefused, # and if a bad recipient, it would raise # SMTPRecipientsRefused; unfortunately on our new host it # raises SMTPRecipientsRefused for BOTH cases. So on HM # we need to check the text of the error to see whether # it's a bad sender or bad recipient. Details: # # BAD SENDER on old host: SMTPSenderRefused: (553, '5.3.0 # ... No such user at our.org', # 'badsendertest@our.org') # # BAD SENDER on new host: SMTPRecipientsRefused: # {'webmaster@our.org': (550, 'Verification failed for # \nNo Such User Here"\nSender # verify failed')} # # BAD RECIPIENT on old host: SMTPRecipientsRefused: # {'badrecipienttest@our.org': (553, '5.3.0 # ... No such user at our.org')} # # BAD RECIPIENT on new host: SMTPRecipientsRefused: # {'badrecipienttest@our.org': (550, 'No Such User # Here"')} # # So logic we'll go for is: # if it's smtplib.SMTPException: # if it's smtplib.SMTPRecipientsRefused: # if it says sender verify failed: raise SMTPSenderRefused # else: re-raise smtplib.SMTPRecipientsRefused # else if it's anything else (incl smtplib.SMTPSenderRefused): # just re-raise # else (not smtplib.SMTPException): just re-raise whatever it is try: errors = server.sendmail(fromaddr, tolist, message) except smtplib.SMTPException, v: # This whole section is really a hack for new host; see above if (re.search('Sender verify failed', str(v))): errdict = v[0] errinfo = errdict[errdict.keys()[0]] # first bad recip code = errinfo[0] # 0 is errcode, 1 is errmsg domain = re.sub('^.*@', '', fromaddr) raise smtplib.SMTPSenderRefused(code, domain, fromaddr) else: raise except Exception: raise server.quit # If there are problems, use this to print info to STDERR (log) #for badaddr in errors.keys(): # errlist = errors[badaddr] # errcode = errlist[0] # errdesc = errlist[1] # print >> sys.stderr, 'Warning: Error sending mail to ' + \ # badaddr + ' -', # print >> sys.stderr, str(errcode) + ': ' + errdesc if __name__ == '__main__': email = EMail() email.send_mail('Test message', 'Test subject', 'info-manager@our.org', 'webmaster@our.org') print "Done."