- just call sendmail instead of using smtplib. sendmail is required for
authorMark Huang <mlhuang@cs.princeton.edu>
Tue, 16 Jan 2007 17:02:52 +0000 (17:02 +0000)
committerMark Huang <mlhuang@cs.princeton.edu>
Tue, 16 Jan 2007 17:02:52 +0000 (17:02 +0000)
  MyPLC anyway, and gets us queueing for free.

PLC/sendmail.py

index 408f2cb..aa7c8eb 100644 (file)
-import smtplib
-import string
+import os
 import sys
-import time
+from types import StringTypes
+from subprocess import Popen, PIPE
 
+from PLC.Debug import log
 from PLC.Faults import *
 
-"""
-used to send out emails - sets up the headers correctly
-"""
-class sendmail:
-
-    def __init__(self, config):
-
-       self.MAIL_ENABLED = config.PLC_MAIL_ENABLED
-
-        self.SMTP_SERVER= 'localhost'
-    
-        self.X_MAILER= 'PlanetLab API Mailer'
-
-
-    """
-    open up a connect to our mail server, and send out a message.
-
-    the email addresses are not verified before sending out the message.
-
-    to_addr_list, cc_addr_list, and from_addr should be a dictionary, with the keys
-    being the email address and the value being the plain text name of
-    the recipient. only the first key from from_addr will be used, so it should
-    contain only one address.
-
-    subject is not checked for multiple lines - ensure it is only one.
-    """
-    def mail( self, to_addr_list, cc_addr_list, from_addr, subject, content ):
-
-       if self.MAIL_ENABLED == 0:
-            return 1
-        
-        server= smtplib.SMTP(self.SMTP_SERVER)
-
-        str_date= time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime())
-
-        str_from_addr= self.create_recipient_list(from_addr,1)
-        str_to_addr= self.create_recipient_list(to_addr_list)
-
-        full_message  = ""
-        full_message += "Content-type: text/plain; charset=iso-8859-1\r\n"
-        full_message += "Date: %s\r\n" % str_date
-        full_message += "MIME-Version: 1.0\r\n"
-
-        full_message += "To: %s\r\n" % str_to_addr
-        full_message += "From: %s\r\n" % str_from_addr
-        
-        if cc_addr_list is not None and len(cc_addr_list) > 0:
-            str_cc_addr= self.create_recipient_list(cc_addr_list)
-            full_message += "Cc: %s\r\n" % str_cc_addr
-
-        full_message += "Subject: %s\r\n" % subject
-        full_message += "Reply-To: %s\r\n" % str_from_addr
-        full_message += "X-Mailer: %s\r\n\r\n" % self.X_MAILER        
-        full_message += content
-
-        try:
-            # get just a list of to recipients (needed for envelope). this
-            # needs to include all reciepients, including Cc
-            local_to_list= to_addr_list.copy()
-
-            if cc_addr_list is not None:
-                local_to_list.update( cc_addr_list )
-                
-            all_to_addr_list= self.create_recipient_list(local_to_list,
-                                                         return_string=0)
-            
-            # send out the mail!
-           rc= server.sendmail(str_from_addr, all_to_addr_list, full_message )
-
-           return 1
-        
-        except smtplib.SMTPRecipientsRefused, err:
-            sys.stderr.write( "SMTPRecipientsRefused: %s" % repr(err) )
-            return 0
-        
-        except smtplib.SMTPHeloError:
-            sys.stderr.write( "SMTPHeloError: %s" % repr(err) )
-            return 0
-        
-        except smtplib.SMTPSenderRefused:
-            sys.stderr.write( "SMTPSenderRefused: %s" % repr(err) )
-            return 0
-        
-        except smtplib.SMTPDataError:
-            sys.stderr.write( "SMTPDataError: %s" % repr(err) )
-            return 0
-        
-
-
-
-
+def sendmail(api, To, Subject, Body, From = None, Cc = "", Bcc = "", DSN = "never"):
     """
-    accepts a list of email recipient as a dictionary in the same format
-    as the mail function, and returns it in a format suitable for use in
-    an email message. for example:
-
-    if limit is specified, only limit number of entries from
-    addr_list is used. which one is used is not defined, so it is really only
-    useful to make sure that the result has a single entry (for from lines)
-
-    for return_string= 1:
-      input: {'user@domain.com': 'A User','test@planet-lab.org': 'PL User'}
-      ouput: 'A User <user@domain.com>, PL User <test@planet-lab.org>'
-    otherwise:
-      input: {'user@domain.com': 'A User','test@planet-lab.org': 'PL User'}
-      ouput: ['A User <user@domain.com>', 'PL User <test@planet-lab.org>']
-  
+    Uses sendmail (must be installed and running locally) to send a
+    message to the specified recipients. If the API is running under
+    mod_python, the apache user must be listed in e.g.,
+    /etc/mail/trusted-users.
+
+    If dsn is not 'never' (e.g., 'failure', 'delay', or 'success'),
+    then the current support address (PLC_MAIL_SUPPORT_ADDRESS) will
+    receive any delivery status notification messages.
     """
-    def create_recipient_list( self, addr_list, return_string= 1, limit= None ):
-        if not isinstance(addr_list,dict):
-            raise PLCAPIError, \
-                  "Internal error, call to create_recipient_list " \
-                  "with non-dict addr_list (%s)." % str(addr_list)
-        
-        if limit == None:
-            limit= len(addr_list.keys())
 
-        if limit <= 0:
-            return ''
+    # Fix up defaults
+    if From is None:
+        From = "%s Support <%s>" % \
+               (api.config.PLC_NAME, api.config.PLC_MAIL_SUPPORT_ADDRESS)
 
-        recipients= []
-        total= 0
-        
-        for email in addr_list.keys():
-            recipients = recipients + ['%s <%s>' % (addr_list[email],email)]
-            total= total+1
-            if total == limit:
-                break
+    header = {'From': From,
+              'version': sys.version.split(" ")[0],
+              'Subject': Subject}
 
-        if return_string == 1:
-            return string.join( recipients, ", " )
+    # Accept either a string or a list of strings for each of To, Cc, and Bcc
+    for line in 'To', 'Cc', 'Bcc':
+        addresses = locals()[line]
+        if isinstance(addresses, StringTypes):
+            header[line] = addresses
         else:
-            return recipients
-
-    
-        
-            
+            header[line] = ", ".join(addresses)
+
+    if not api.config.PLC_MAIL_ENABLED:
+        print >> log, "From: %(From)s, To: %(To)s, Subject: %(Subject)s" % header
+        return
+
+    p = Popen(["sendmail", "-N", DSN, "-t", "-f" + api.config.PLC_MAIL_SUPPORT_ADDRESS],
+              stdin = PIPE, stdout = PIPE, stderr = PIPE)
+
+    # Write headers
+    p.stdin.write("""
+Content-type: text/plain
+From: %(From)s
+Reply-To: %(From)s
+To: %(To)s
+Cc: %(Cc)s
+Bcc: %(Bcc)s
+X-Mailer: Python/%(version)s
+Subject: %(Subject)s
+
+""".lstrip() % header)
+
+    # Write body
+    p.stdin.write(Body)
+
+    p.stdin.close()
+    err = p.stderr.read()
+    rc = p.wait()
+
+    # Done
+    if rc != 0:
+        raise PLCAPIError, err