appypod-rattail/gen/mail.py

139 lines
5.5 KiB
Python
Raw Normal View History

'''This package contains functions for sending email notifications.'''
2012-05-08 07:49:45 -05:00
import smtplib, socket
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email import Encoders
from email.Header import Header
from appy.shared.utils import sequenceTypes
# ------------------------------------------------------------------------------
def sendMail(tool, to, subject, body, attachments=None):
'''Sends a mail, via p_tool.mailHost, to p_to (a single email address or a
list of email addresses).'''
# Just log things if mail is disabled
fromAddress = tool.mailFrom
if not tool.mailEnabled or not tool.mailHost:
if not tool.mailHost:
msg = ' (no mailhost defined)'
else:
msg = ''
tool.log('Mail disabled%s: should send mail from %s to %s.' % \
(msg, fromAddress, str(to)))
tool.log('Subject: %s' % subject)
tool.log('Body: %s' % body)
if attachments:
tool.log('%d attachment(s).' % len(attachments))
return
tool.log('Sending mail from %s to %s (subject: %s).' % \
(fromAddress, str(to), subject))
# Create the base MIME message
body = MIMEText(body, 'plain', 'utf-8')
if attachments:
msg = MIMEMultipart()
msg.attach( body )
else:
msg = body
# Add the header values
msg['Subject'] = Header(subject, 'utf-8')
msg['From'] = fromAddress
if isinstance(to, basestring):
msg['To'] = to
else:
if len(to) == 1:
msg['To'] = to[0]
else:
msg['To'] = fromAddress
msg['Bcc'] = ', '.join(to)
to = fromAddress
# Add attachments
if attachments:
for fileName, fileContent in attachments:
part = MIMEBase('application', 'octet-stream')
2012-05-08 07:49:45 -05:00
if fileContent.__class__.__name__ == 'FileWrapper':
fileContent = fileContent._zopeFile
if hasattr(fileContent, 'data'):
# It is a File instance coming from the database
data = fileContent.data
if isinstance(data, basestring):
payLoad = data
else:
payLoad = ''
while data is not None:
payLoad += data.data
data = data.next
else:
payLoad = fileContent
part.set_payload(payLoad)
Encoders.encode_base64(part)
part.add_header('Content-Disposition',
'attachment; filename="%s"' % fileName)
msg.attach(part)
# Send the email
try:
smtpInfo = tool.mailHost.split(':', 3)
login = password = None
if len(smtpInfo) == 2:
# We simply have server and port
server, port = smtpInfo
else:
# We also have login and password
server, port, login, password = smtpInfo
smtpServer = smtplib.SMTP(server, port=int(port))
if login:
smtpServer.login(login, password)
res = smtpServer.sendmail(fromAddress, [to], msg.as_string())
smtpServer.quit()
if res:
tool.log('Could not send mail to some recipients. %s' % str(res),
type='warning')
except smtplib.SMTPException, e:
tool.log('Mail sending failed: %s' % str(e), type='error')
2012-05-08 07:49:45 -05:00
except socket.error, se:
tool.log('Mail sending failed: %s' % str(se), type='error')
# ------------------------------------------------------------------------------
def sendNotification(obj, transition, transitionName, workflow):
'''Sends mail about p_transition named p_transitionName, that has been
triggered on p_obj that is controlled by p_workflow.'''
from appy.gen.descriptors import WorkflowDescriptor
wfName = WorkflowDescriptor.getWorkflowName(workflow.__class__)
zopeObj = obj.o
tool = zopeObj.getTool()
mailInfo = transition.notify(workflow, obj)
if not mailInfo[0]: return # Send a mail to nobody.
# mailInfo may be one of the following:
# (to,)
# (to, cc)
# (to, mailSubject, mailBody)
# (to, cc, mailSubject, mailBody)
# "to" and "cc" maybe simple strings (one simple string = one email
# address or one role) or sequences of strings.
# Determine mail subject and body.
if len(mailInfo) <= 2:
# The user didn't mention mail body and subject. We will use those
# defined from i18n labels.
wfHistory = zopeObj.getHistory()
labelPrefix = '%s_%s' % (wfName, transitionName)
tName = obj.translate(labelPrefix)
keys = {'siteUrl': tool.getPath('/').absolute_url(),
'siteTitle': tool.getAppName(),
'objectUrl': zopeObj.absolute_url(),
'objectTitle': zopeObj.Title(),
'transitionName': tName,
'transitionComment': wfHistory[0]['comments']}
mailSubject = obj.translate(labelPrefix + '_mail_subject', keys)
mailBody = obj.translate(labelPrefix + '_mail_body', keys)
else:
mailSubject = mailInfo[-1]
mailBody = mailInfo[-2]
# Determine "to" and "cc".
to = mailInfo[0]
cc = []
if (len(mailInfo) in (2,4)) and mailInfo[1]: cc = mailInfo[1]
if type(to) not in sequenceTypes: to = [to]
if type(cc) not in sequenceTypes: cc = [cc]
# Send the mail
sendMail(tool.appy(), to, mailSubject, mailBody)
# ------------------------------------------------------------------------------