smtplib hack

Dennis Voss dennis at dennis-voss.de
Sat Jul 28 13:58:26 EDT 2001


Hi,

I patched the smtplib to support sending email via sendmail also.
With this addon, you should be able to do:

import smtplib2

mysendmailexe = "/usr/sbin/sendmail"

fromaddr = "dennis at dennis-voss.de"
toaddr = "dennis.voss at tu-harburg.de"
message = "Just a quick test for the smtplib enhancement\n"

server = smtplib2.SMTP(mysendmailexe)
server.sendmail(fromaddr, toaddr, message)
server.quit()

The code is largely beta and in some parts untested.
However, swapping sendmail and a fully fledged is nice and
hopefully welcomed in cgi.

Here's the diff -u:
--- smtplib.py Mon Jun 18 21:38:06 2001
+++ smtplib2.py Sat Jul 28 19:09:18 2001
@@ -36,6 +36,7 @@
 #     Eric S. Raymond <esr at thyrsus.com>
 # Better RFC 821 compliance (MAIL and RCPT, and CRLF in data)
 #     by Carey Evans <c.evans at clear.net.nz>, for picky mail servers.
+# Sendmail interface added by Dennis Voss <dennis at dennis-voss.de>
 #
 # This was modified from the Python 1.5 library HTTP lib.

@@ -111,6 +112,9 @@
 class SMTPHeloError(SMTPResponseException):
     """The server refused our HELO reply."""

+class SMTPSendmailError(SMTPResponseException):
+    """sendmail did exit with an error."""
+

 def quoteaddr(addr):
     """Quote a subset of the email addresses defined by RFC 821.
@@ -172,21 +176,26 @@
     helo_resp = None
     ehlo_resp = None
     does_esmtp = 0
+    sendmail_path = ''

     def __init__(self, host = '', port = 0):
         """Initialize a new instance.

         If specified, `host' is the name of the remote host to which to

-        connect.  If specified, `port' specifies the port to which to
connect.
+        connect OR path to sendmail (or compatible) executeable.
+        If specified, `port' specifies the port to which to connect.
         By default, smtplib.SMTP_PORT is used.  An SMTPConnectError is
raised
         if the specified `host' doesn't respond correctly.

         """
         self.esmtp_features = {}
         if host:
-            (code, msg) = self.connect(host, port)
-            if code != 220:
-                raise SMTPConnectError(code, msg)
+            if host[0] == '/':
+                self.sendmail_path = host
+            else:
+                (code, msg) = self.connect(host, port)
+                if code != 220:
+                    raise SMTPConnectError(code, msg)

     def set_debuglevel(self, debuglevel):
         """Set the debug output level.
@@ -464,6 +473,17 @@
         empty dictionary.

         """
+        if self.sendmail_path:
+            import os
+            p = os.popen("%s -t" % self.sendmail_path, "w")
+            p.write("From: %s\n" % from_addr)
+            p.write("To: %s\n" % to_addrs)
+            p.write("\n") # blank line separating headers from body
+            p.write("%s\n" % msg)
+            sts = p.close()
+            if sts != 0:
+                raise SMTPSendmailError
+
         if self.helo_resp is None and self.ehlo_resp is None:
             if not (200 <= self.ehlo()[0] <= 299):
                 (code,resp) = self.helo()


My diff program did not recognize the two extra lines in the sendmail()
function:
-       (code,resp) = self.mail(from_addr, esmtp_opts)
+       if not self.sendmail_path:
+            (code,resp) = self.mail(from_addr, esmtp_opts)

-            (code,resp) = self.data(msg)
+       if not self.sendmail_path:
+            (code,resp) = self.data(msg)

And the new quit() function:
    def quit(self):
        """Terminate the SMTP session."""
        if not self.sendmail_path:
            self.docmd("quit")
            self.close()


Further encapsulation is needed, but I generally only use these.


Dennis Voss




More information about the Python-list mailing list