Back to index

plone3  3.1.7
mail.py
Go to the documentation of this file.
00001 ##############################################################################
00002 #
00003 # Copyright (c) 2004 Christian Heimes and Contributors.
00004 # All Rights Reserved.
00005 #
00006 # This software is subject to the provisions of the Zope Public License,
00007 # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
00008 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
00009 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00010 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
00011 # FOR A PARTICULAR PURPOSE.
00012 #
00013 ##############################################################################
00014 """
00015 """
00016 from config import X_MAILER
00017 
00018 import os, sys
00019 import smtplib
00020 import email.Message
00021 import email.Utils
00022 import socket
00023 from DateTime import DateTime
00024 from random import randint
00025 
00026 from Products.MailHost.MailHost import MailHostError
00027 
00028 ssl_support = False
00029 if hasattr(socket, 'ssl'):
00030     ssl_support = True
00031 
00032 class Mail:
00033     """A email object which knows how to send itself
00034 
00035     mfrom     - mail from tag (only for SMTP server)
00036     mto       - mail to tag (only for SMTP server)
00037     message   - The message email.Message.Message based object
00038     smtp_host - SMTP server address
00039     smtp_port - SMTP server port
00040     **kwargs  - additional keywords like userid, password and forceTLS
00041     """
00042 
00043     def __init__(self, mfrom, mto, message,
00044                  smtp_host='localhost', smtp_port=25,
00045                  **kwargs):
00046         self.mfrom = mfrom
00047         self.mto = mto
00048         # message must be email.Message.Message based
00049         assert(isinstance(message, email.Message.Message))
00050         # Add some important headers
00051         if not message.has_key('Date'):
00052             message['Date'] = DateTime().rfc822()
00053         if not message.has_key('X-Mailer'):
00054             message['X-Mailer'] = X_MAILER
00055         if not message.has_key('Message-Id'):
00056             fqdn = socket.getfqdn()
00057             message['Message-Id'] = email.Utils.make_msgid(fqdn)
00058 
00059         self.message = message
00060 
00061         self.host = smtp_host
00062         self.port = int(smtp_port)
00063 
00064         self.kwargs = kwargs
00065         self.errors = 0
00066         self.id = None
00067 
00068     def setId(self, id):
00069         """Set the unique id of the email
00070         """
00071         self.id = id
00072 
00073     def getId(self):
00074         """Get unique id
00075         """
00076         return self.id
00077 
00078     def incError(self):
00079         """Increase the error counter
00080         """
00081         self.errors+=1
00082 
00083     def getErrors(self):
00084         """Get the error counter
00085         """
00086         return self.errors
00087 
00088     def send(self, debug=False):
00089         """Send email to the SMTP server
00090         """
00091         kw = self.kwargs
00092         userid   = kw.get('userid', None)
00093         password = kw.get('password', None)
00094         forceTLS = kw.get('forcetls', False)
00095         noTLS    = kw.get('notls', False)
00096         message  = self.message.as_string()
00097 
00098         # connect
00099         if not self.host:
00100             raise MailHostError('No mailserver has been configured')
00101 
00102         smtpserver = smtplib.SMTP(self.host, self.port)
00103         if debug:
00104             smtpserver.set_debuglevel(1)
00105 
00106         # Try EHLO first, then HELO.
00107         if not (200 <= smtpserver.ehlo()[0] <= 299):
00108             (code, resp) = smtpserver.helo()
00109             if not (200 <= code <= 299):
00110                 raise MailHostError('Host refused to talk to us: %s' % resp)
00111 
00112         # check for ssl encryption
00113         if smtpserver.has_extn('starttls') and ssl_support and not(noTLS):
00114             smtpserver.starttls()
00115             smtpserver.ehlo()
00116         elif forceTLS:
00117             if noTLS:
00118                 raise MailHostError('Configured not to try TLS '
00119                     'but it is required')
00120             else:
00121                 raise MailHostError('Host does NOT support StartTLS '
00122                     'but it is required')
00123         # login
00124         if smtpserver.does_esmtp:
00125             if userid:
00126                 smtpserver.login(userid, password)
00127         elif userid:
00128             #indicate error here to prevent inadvertent use of spam relay
00129             raise MailHostError('Host does NOT support ESMTP '
00130                                 'but username/password provided')
00131         # send and quit
00132         smtpserver.sendmail(self.mfrom, self.mto, message)
00133         smtpserver.quit()
00134 
00135     def __str__(self):
00136         return self.message.as_string()
00137 
00138     def __repr__(self):
00139         return '<%s (%s) at %s>' % (
00140             self.__class__.__name__, self.info(),
00141             id(self))
00142 
00143     def info(self):
00144         """Return status informations about the email
00145         """
00146         return ('From: %(from)s, To: %(to)s, Subject: %(subject)s '
00147                 '(s:%(size)d, e:%(errors)d)' % {
00148             'id' : self.getId(), 'errors' : self.errors,
00149             'from' : self.message['From'], 'to' : self.message['To'],
00150             'subject' : self.message['Subject'], 'size' : len(self.message)
00151             })