File: mailer.py

package info (click to toggle)
python-jtoolkit 0.7.8-2
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 1,436 kB
  • ctags: 2,536
  • sloc: python: 15,143; makefile: 20
file content (286 lines) | stat: -rwxr-xr-x 10,832 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""provides a simple wrapper for composing and sending emails via smtp or MAPI"""

# Copyright 2002, 2003 St James Software
# 
# This file is part of jToolkit.
#
# jToolkit 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.
# 
# jToolkit 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 jToolkit; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

###################### SMTP code ######################

import smtplib
import socket
import mimetypes
from email.Encoders import encode_base64
from email.MIMEBase import MIMEBase
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText

# some constants for messages
contentheader = \
"""Content-Type: %s;
	charset = "%s"
"""
mimeversion = "MIME-Version: 1.0\n"
contenttransferencoding = "Content-Transfer-Encoding: 8bit\n"

def makemessage(messagedict, attachmentlist=[]):
  #attachmentlist is a list of tuples containing the physical filename, and the required filename
  #eg. [('c:\\testme.pdf', 'testme.pdf'), ('c:\\oracle\\oradata\\mydb\\system01.dbf', 'reallybigspam.txt')]
  attachments = []
  for thefile in attachmentlist:    #make a list of attachments as text to be added
    attachments.append(makeAttachment(thefile[0], thefile[1]))
  messagecharset = messagedict.get('charset','utf8')
  message = contentheader % (messagedict.get('contenttype', 'text/plain'),
                             messagecharset)
  if 'from' in messagedict:
    message += "From: %s\n" % messagedict['from']
  if 'organization' in messagedict:
    message += "Organization: %s\n" % messagedict['organization']
  if 'to' in messagedict:
    recipients = messagedict['to']
    if isinstance(recipients, (str, unicode)):
      recipients = recipients.split(",")
    message += "To: %s\n" % ", ".join(recipients)
  if 'subject' in messagedict:
    message += "Subject: %s\n" % messagedict['subject']
  if 'reply-to' in messagedict:
    message += "Reply-To: %s\n" % messagedict['reply-to']
  try:
    import email.Utils
    message += "Date: %s\n" % email.Utils.formatdate(localtime=True)
  except:
    raise
  if attachmentlist:
    msgbody = MIMEMultipart()
    if 'body' in messagedict:
      msgbody.attach(MIMEText(messagedict['body']))
    for file in attachments:
      msgbody.attach(file)
    message += msgbody.as_string()
  else:
    message += mimeversion + contenttransferencoding + "\n"
    if 'body' in messagedict:
      message += messagedict['body']

  # Make sure the entire message is encoded using the stated charset
  message = message.encode(messagecharset)
  return message

def makeAttachment(attachedFile, Outfile):
    ctype = 'application/octet-stream'
    fileIn = open(attachedFile, 'rb')
    attachment = MIMEBase('application', 'octet-stream')
    attachment.set_payload(fileIn.read())
    encode_base64(attachment)
    fileIn.close
    attachment.add_header('Content-Disposition', 'attachment',filename=Outfile)
    return attachment

def dosendmessage(fromemail,recipientemails,message,smtpserver='',errorhandler=None):
  smtp = smtplib.SMTP()
  errmsg = ""
  try:
    smtp.connect(smtpserver)
    refused = smtp.sendmail(fromemail,recipientemails,message)
    errmsg += ", ".join(refused.keys())
    if errmsg != "":
      errmsg = "Recipients " + errmsg + " refused"
  except smtplib.SMTPRecipientsRefused:
    errmsg += "All recipients refused"
  except smtplib.SMTPHeloError:
    errmsg += "Server didn't respond properly to HELO"
  except smtplib.SMTPSenderRefused:
    errmsg += "Sender refused"
  except smtplib.SMTPDataError:
    errmsg += "Unexpected error code"
  except UnicodeEncodeError:
      errmsg += "Error in transporting message due to a unicode encoding error"
      if errorhandler is not None:
        errmsg += ": %r" % errorhandler.exception_str()
  except socket.error, msg:
    if errorhandler is not None:
      errmsg += "Socket Error: %r" % errorhandler.exception_str()
  if smtp.sock:
    smtp.quit()
  if errmsg != "" and errorhandler is not None:
    errorhandler.logerror(errmsg)
  return errmsg

def SendSMTPMail(Subject="", Message="", SendTo=None, SendCC=None, SendBCC=None, SendFrom=None, SMTPServer=None, errorhandler=None):
  # currently SendFrom must be a tuple: label, address
  fromlabel, fromaddress = SendFrom
  toaddresses = ccaddresses = bccaddresses = []
  if SendTo is not None:
    toaddresses = [addr.strip() for addr in SendTo.split(",")]
  if SendCC is not None:  
    ccaddresses = [addr.strip() for addr in SendCC.split(",")]
  if SendBCC is not None:
    bccaddresses = [addr.strip() for addr in SendBCC.split(",")]
  recipients = toaddresses + ccaddresses + bccaddresses
  messagedict = {"from": "%s <%s>" % (fromlabel, fromaddress),
                 "to": toaddresses,
                 "cc": ccaddresses,
                 "bcc": bccaddresses,
                 "subject": Subject,
                 "body": Message}
  message = makemessage(messagedict)
  dosendmessage(fromaddress, recipients, message, SMTPServer, errorhandler)

###################### Simple MAPI code ######################

def SetRecipients(Message,Recipients,RecipientType):
   """add recipient names to list"""
   for recipient in Recipients.split(','):
      recip = Message.Recipients.Add(Name=recipient, Type=RecipientType)
      recip.Resolve()

def SendMAPIMail(Subject="", Message="", SendTo=None, SendCC=None, SendBCC=None, MAPIProfile=None):
   """method used to send mapi email, pass email address, subject, MAPIprofile and message"""
   # Create a mapi session
   import win32com.client.dynamic
   mapi = win32com.client.dynamic.Dispatch("MAPI.session")

   if MAPIProfile:
     mapi.Logon(MAPIProfile)
   else:
     mapi.Logon()

   # Create a new message
   outbox = mapi.OutBox.Messages.Add(Subject,Message,'CMC: IPM')

   # Set the recipients
   if SendTo:
     SetRecipients(outbox,SendTo,1)
   if SendCC:
     SetRecipients(outbox,SendCC,2)
   if SendBCC:
     SetRecipients(outbox,SendBCC,3)

   # Update and send the message
   outbox.Update()
   outbox.Send()
   mapi.DeliverNow()

   # terminate the MAPI session and kill the objects   
   mapi.Logoff()
   outbox = None
   mapi = None

###################### Extended MAPI code ######################


def SendEMAPIMail(Subject="", Message="", SendTo=None, SendCC=None, SendBCC=None, MAPIProfile=None):
    """
    Sends an email to the recipient using the extended MAPI interface
    """
    from win32com.mapi import mapi,mapitags,mapiutil

    # initialize and log on
    mapi.MAPIInitialize(None)
    session = mapi.MAPILogonEx(0, MAPIProfile, None, mapi.MAPI_EXTENDED | mapi.MAPI_USE_DEFAULT)
    adminprofiles = mapi.MAPIAdminProfiles(0)
    messagestorestable = session.GetMsgStoresTable(0)
    statustable = session.GetStatusTable(0)
    messagestorestable.SetColumns((mapitags.PR_ENTRYID, mapitags.PR_DISPLAY_NAME_A, mapitags.PR_DEFAULT_STORE),0)

##    #this shows a how to make a restriction. it might be useful later
##    restrictionType = (mapi.RES_PROPERTY,(mapi.RELOP_EQ,mapitags.PR_DEFAULT_STORE,(mapitags.PT_BOOLEAN,True)))
##    messagestorestable.Restrict(restrictionType,0)

    while True:
        rows = messagestorestable.QueryRows(1, 0)
        #if this is the last row then stop
        if len(rows) != 1:
            break
        row = rows[0]
        #if this is the default store then stop
        if ((mapitags.PR_DEFAULT_STORE,True) in row):
            break

    # unpack the row and open the message store
    (eid_tag, eid), (name_tag, name), (def_store_tag, def_store) = row
    msgstore = session.OpenMsgStore(0,eid,None,mapi.MDB_NO_DIALOG | mapi.MAPI_BEST_ACCESS)

    # get the outbox
    hr, props = msgstore.GetProps((mapitags.PR_IPM_OUTBOX_ENTRYID), 0)
    (tag, eid) = props[0]
    #check for errors
    if mapitags.PROP_TYPE(tag) == mapitags.PT_ERROR:
        raise TypeError,'got PT_ERROR instead of PT_BINARY: %s'%eid
    outboxfolder = msgstore.OpenEntry(eid,None,mapi.MAPI_BEST_ACCESS)

    # create the message and the addrlist
    message = outboxfolder.CreateMessage(None,0)
   
    pal = []
    def makeentry(recipient, recipienttype):
      return ((mapitags.PR_RECIPIENT_TYPE, recipienttype),
              (mapitags.PR_SEND_RICH_INFO, False),
              (mapitags.PR_DISPLAY_TYPE, 0),
              (mapitags.PR_OBJECT_TYPE, 6),
              (mapitags.PR_EMAIL_ADDRESS_A, recipient),
              (mapitags.PR_ADDRTYPE_A, 'SMTP'),
              (mapitags.PR_DISPLAY_NAME_A, recipient))
    
    if SendTo:
      pal.extend([makeentry(recipient, mapi.MAPI_TO) for recipient in SendTo.split(",")])
    if SendCC:
      pal.extend([makeentry(recipient, mapi.MAPI_CC) for recipient in SendCC.split(",")])
    if SendBCC:
      pal.extend([makeentry(recipient, mapi.MAPI_BCC) for recipient in SendBCC.split(",")])

    #f = open('c:\\nexsig.gif')
    
    # add the resolved recipients to the message
    message.ModifyRecipients(mapi.MODRECIP_ADD,pal)
    #iAttach = message.CreateAttach(None,0)
    #iAttach[1].SetProps([(mapitags.NUM_ATT_PROPS, 5),
                         #(mapitags.PR_ATTACH_METHOD, mapi.ATTACH_BY_VALUE),
                         #(mapitags.PR_ATTACH_LONG_FILENAME, 'test.gif'),
                         #(mapitags.PR_ATTACH_FILENAME, 'test.gif'),
                         #(mapitags.PR_ATTACH_EXTENSION, '.gif'),
                         #(mapitags.PR_ATTACH_NUM, iAttach[0]),
                         #(mapitags.PR_DISPLAY_NAME, 'test.gif'),
                         #(mapitags.PR_ATTACH_DATA_BIN, f.read()),
                         #(mapitags.PR_ATTACH_ENCODING, 'FLAANSAAS'),
                         #])
    #f.close()
    message.SetProps([(mapitags.PR_BODY_A,Message),
                      (mapitags.PR_SUBJECT_A,Subject)])

    #iAttach[1].SaveChanges(0)
    # save changes and submit
    outboxfolder.SaveChanges(0)
    message.SubmitMessage(0)

def test():
   MAPIProfile = "mail.sjsoft.com"
   SendTo = "test@sjsoft.com"
   SendCC = None
   SendBCC = None
   SendMessage = "testing one two three"
   # SendSubject = "Testing Simple MAPI!!"
   # SendMAPIMail(SendSubject, SendMessage, SendTo, MAPIProfile=MAPIProfile)
   SendSubject = "Testing Extended MAPI!!"
   print SendSubject
   SendEMAPIMail(SendSubject, SendMessage, SendTo, MAPIProfile=MAPIProfile)

if __name__ == '__main__':
  test()