1# Caolan McNamara caolanm@redhat.com 2# a simple email mailmerge component 3 4# manual installation for hackers, not necessary for users 5# cp mailmerge.py /usr/lib/openoffice.org2.0/program 6# cd /usr/lib/openoffice.org2.0/program 7# ./unopkg add --shared mailmerge.py 8# edit ~/.openoffice.org2/user/registry/data/org/openoffice/Office/Writer.xcu 9# and change EMailSupported to as follows... 10# <prop oor:name="EMailSupported" oor:type="xs:boolean"> 11# <value>true</value> 12# </prop> 13 14import unohelper 15import uno 16import re 17 18#to implement com::sun::star::mail::XMailServiceProvider 19#and 20#to implement com.sun.star.mail.XMailMessage 21 22from com.sun.star.mail import XMailServiceProvider 23from com.sun.star.mail import XMailService 24from com.sun.star.mail import XSmtpService 25from com.sun.star.mail import XConnectionListener 26from com.sun.star.mail import XAuthenticator 27from com.sun.star.mail import XMailMessage 28from com.sun.star.mail.MailServiceType import SMTP 29from com.sun.star.mail.MailServiceType import POP3 30from com.sun.star.mail.MailServiceType import IMAP 31from com.sun.star.uno import XCurrentContext 32from com.sun.star.lang import IllegalArgumentException 33from com.sun.star.lang import EventObject 34from com.sun.star.mail import SendMailMessageFailedException 35 36from email.MIMEBase import MIMEBase 37from email.Message import Message 38from email import Encoders 39from email.Header import Header 40from email.MIMEMultipart import MIMEMultipart 41from email.Utils import formatdate 42from email.Utils import parseaddr 43 44import sys, smtplib, imaplib, poplib 45 46dbg = False 47 48class PyMailSMTPService(unohelper.Base, XSmtpService): 49 def __init__( self, ctx ): 50 self.ctx = ctx 51 self.listeners = [] 52 self.supportedtypes = ('Insecure', 'Ssl') 53 self.server = None 54 self.connectioncontext = None 55 self.notify = EventObject() 56 if dbg: 57 print >> sys.stderr, "PyMailSMPTService init" 58 def addConnectionListener(self, xListener): 59 if dbg: 60 print >> sys.stderr, "PyMailSMPTService addConnectionListener" 61 self.listeners.append(xListener) 62 def removeConnectionListener(self, xListener): 63 if dbg: 64 print >> sys.stderr, "PyMailSMPTService removeConnectionListener" 65 self.listeners.remove(xListener) 66 def getSupportedConnectionTypes(self): 67 if dbg: 68 print >> sys.stderr, "PyMailSMPTService getSupportedConnectionTypes" 69 return self.supportedtypes 70 def connect(self, xConnectionContext, xAuthenticator): 71 self.connectioncontext = xConnectionContext 72 if dbg: 73 print >> sys.stderr, "PyMailSMPTService connect" 74 server = xConnectionContext.getValueByName("ServerName") 75 if dbg: 76 print >> sys.stderr, server 77 port = xConnectionContext.getValueByName("Port") 78 if dbg: 79 print >> sys.stderr, port 80 self.server = smtplib.SMTP(server, port) 81 if dbg: 82 self.server.set_debuglevel(1) 83 connectiontype = xConnectionContext.getValueByName("ConnectionType") 84 if dbg: 85 print >> sys.stderr, connectiontype 86 if connectiontype == 'Ssl': 87 self.server.ehlo() 88 self.server.starttls() 89 self.server.ehlo() 90 91 user = xAuthenticator.getUserName().encode('ascii') 92 password = xAuthenticator.getPassword().encode('ascii') 93 if user != '': 94 if dbg: 95 print >> sys.stderr, 'Logging in, username of', user 96 self.server.login(user, password) 97 98 for listener in self.listeners: 99 listener.connected(self.notify) 100 def disconnect(self): 101 if dbg: 102 print >> sys.stderr, "PyMailSMPTService disconnect" 103 if self.server: 104 self.server.quit() 105 self.server = None 106 for listener in self.listeners: 107 listener.disconnected(self.notify) 108 def isConnected(self): 109 if dbg: 110 print >> sys.stderr, "PyMailSMPTService isConnected" 111 return self.server != None 112 def getCurrentConnectionContext(self): 113 if dbg: 114 print >> sys.stderr, "PyMailSMPTService getCurrentConnectionContext" 115 return self.connectioncontext 116 def sendMailMessage(self, xMailMessage): 117 COMMASPACE = ', ' 118 119 if dbg: 120 print >> sys.stderr, "PyMailSMPTService sendMailMessage" 121 recipients = xMailMessage.getRecipients() 122 sendermail = xMailMessage.SenderAddress 123 sendername = xMailMessage.SenderName 124 subject = xMailMessage.Subject 125 ccrecipients = xMailMessage.getCcRecipients() 126 bccrecipients = xMailMessage.getBccRecipients() 127 if dbg: 128 print >> sys.stderr, "PyMailSMPTService subject", subject 129 print >> sys.stderr, "PyMailSMPTService from", sendername.encode('utf-8') 130 print >> sys.stderr, "PyMailSMTPService from", sendermail 131 print >> sys.stderr, "PyMailSMPTService send to", recipients 132 133 attachments = xMailMessage.getAttachments() 134 135 textmsg = Message() 136 137 content = xMailMessage.Body 138 flavors = content.getTransferDataFlavors() 139 if dbg: 140 print >> sys.stderr, "PyMailSMPTService flavors len", len(flavors) 141 142 #Use first flavor that's sane for an email body 143 for flavor in flavors: 144 if flavor.MimeType.find('text/html') != -1 or flavor.MimeType.find('text/plain') != -1: 145 if dbg: 146 print >> sys.stderr, "PyMailSMPTService mimetype is", flavor.MimeType 147 textbody = content.getTransferData(flavor) 148 try: 149 textbody = textbody.value 150 except: 151 pass 152 textbody = textbody.encode('utf-8') 153 154 if len(textbody): 155 mimeEncoding = re.sub("charset=.*", "charset=UTF-8", flavor.MimeType) 156 if mimeEncoding.find('charset=UTF-8') == -1: 157 mimeEncoding = mimeEncoding + "; charset=UTF-8" 158 textmsg['Content-Type'] = mimeEncoding 159 textmsg['MIME-Version'] = '1.0' 160 textmsg.set_payload(textbody) 161 162 break 163 164 if (len(attachments)): 165 msg = MIMEMultipart() 166 msg.epilogue = '' 167 msg.attach(textmsg) 168 else: 169 msg = textmsg 170 171 hdr = Header(sendername, 'utf-8') 172 hdr.append('<'+sendermail+'>','us-ascii') 173 msg['Subject'] = subject 174 msg['From'] = hdr 175 msg['To'] = COMMASPACE.join(recipients) 176 if len(ccrecipients): 177 msg['Cc'] = COMMASPACE.join(ccrecipients) 178 if xMailMessage.ReplyToAddress != '': 179 msg['Reply-To'] = xMailMessage.ReplyToAddress 180 181 mailerstring = "OpenOffice.org 2.0 via Caolan's mailmerge component" 182 try: 183 ctx = uno.getComponentContext() 184 aConfigProvider = ctx.ServiceManager.createInstance("com.sun.star.configuration.ConfigurationProvider") 185 prop = uno.createUnoStruct('com.sun.star.beans.PropertyValue') 186 prop.Name = "nodepath" 187 prop.Value = "/org.openoffice.Setup/Product" 188 aSettings = aConfigProvider.createInstanceWithArguments("com.sun.star.configuration.ConfigurationAccess", 189 (prop,)) 190 mailerstring = aSettings.getByName("ooName") + " " + \ 191 aSettings.getByName("ooSetupVersion") + " via Caolan's mailmerge component" 192 except: 193 pass 194 195 msg['X-Mailer'] = mailerstring 196 msg['Date'] = formatdate(localtime=True) 197 198 for attachment in attachments: 199 content = attachment.Data 200 flavors = content.getTransferDataFlavors() 201 flavor = flavors[0] 202 ctype = flavor.MimeType 203 maintype, subtype = ctype.split('/', 1) 204 msgattachment = MIMEBase(maintype, subtype) 205 data = content.getTransferData(flavor) 206 msgattachment.set_payload(data) 207 Encoders.encode_base64(msgattachment) 208 msgattachment.add_header('Content-Disposition', 'attachment', \ 209 filename=attachment.ReadableName) 210 msg.attach(msgattachment) 211 212 uniquer = {} 213 for key in recipients: 214 uniquer[key] = True 215 if len(ccrecipients): 216 for key in ccrecipients: 217 uniquer[key] = True 218 if len(bccrecipients): 219 for key in bccrecipients: 220 uniquer[key] = True 221 truerecipients = uniquer.keys() 222 223 if dbg: 224 print >> sys.stderr, "PyMailSMPTService recipients are", truerecipients 225 226 self.server.sendmail(sendermail, truerecipients, msg.as_string()) 227 228class PyMailIMAPService(unohelper.Base, XMailService): 229 def __init__( self, ctx ): 230 self.ctx = ctx 231 self.listeners = [] 232 self.supportedtypes = ('Insecure', 'Ssl') 233 self.server = None 234 self.connectioncontext = None 235 if dbg: 236 print >> sys.stderr, "PyMailIMAPService init" 237 def addConnectionListener(self, xListener): 238 if dbg: 239 print >> sys.stderr, "PyMailIMAPService addConnectionListener" 240 self.listeners.append(xListener) 241 def removeConnectionListener(self, xListener): 242 if dbg: 243 print >> sys.stderr, "PyMailIMAPService removeConnectionListener" 244 self.listeners.remove(xListener) 245 def getSupportedConnectionTypes(self): 246 if dbg: 247 print >> sys.stderr, "PyMailIMAPService getSupportedConnectionTypes" 248 return self.supportedtypes 249 def connect(self, xConnectionContext, xAuthenticator): 250 if dbg: 251 print >> sys.stderr, "PyMailIMAPService connect" 252 253 self.connectioncontext = xConnectionContext 254 server = xConnectionContext.getValueByName("ServerName") 255 if dbg: 256 print >> sys.stderr, server 257 port = xConnectionContext.getValueByName("Port") 258 if dbg: 259 print >> sys.stderr, port 260 connectiontype = xConnectionContext.getValueByName("ConnectionType") 261 if dbg: 262 print >> sys.stderr, connectiontype 263 print >> sys.stderr, "BEFORE" 264 if connectiontype == 'Ssl': 265 self.server = imaplib.IMAP4_SSL(server, port) 266 else: 267 self.server = imaplib.IMAP4(server, port) 268 print >> sys.stderr, "AFTER" 269 270 user = xAuthenticator.getUserName().encode('ascii') 271 password = xAuthenticator.getPassword().encode('ascii') 272 if user != '': 273 if dbg: 274 print >> sys.stderr, 'Logging in, username of', user 275 self.server.login(user, password) 276 277 for listener in self.listeners: 278 listener.connected(self.notify) 279 def disconnect(self): 280 if dbg: 281 print >> sys.stderr, "PyMailIMAPService disconnect" 282 if self.server: 283 self.server.logout() 284 self.server = None 285 for listener in self.listeners: 286 listener.disconnected(self.notify) 287 def isConnected(self): 288 if dbg: 289 print >> sys.stderr, "PyMailIMAPService isConnected" 290 return self.server != None 291 def getCurrentConnectionContext(self): 292 if dbg: 293 print >> sys.stderr, "PyMailIMAPService getCurrentConnectionContext" 294 return self.connectioncontext 295 296class PyMailPOP3Service(unohelper.Base, XMailService): 297 def __init__( self, ctx ): 298 self.ctx = ctx 299 self.listeners = [] 300 self.supportedtypes = ('Insecure', 'Ssl') 301 self.server = None 302 self.connectioncontext = None 303 if dbg: 304 print >> sys.stderr, "PyMailPOP3Service init" 305 def addConnectionListener(self, xListener): 306 if dbg: 307 print >> sys.stderr, "PyMailPOP3Service addConnectionListener" 308 self.listeners.append(xListener) 309 def removeConnectionListener(self, xListener): 310 if dbg: 311 print >> sys.stderr, "PyMailPOP3Service removeConnectionListener" 312 self.listeners.remove(xListener) 313 def getSupportedConnectionTypes(self): 314 if dbg: 315 print >> sys.stderr, "PyMailPOP3Service getSupportedConnectionTypes" 316 return self.supportedtypes 317 def connect(self, xConnectionContext, xAuthenticator): 318 if dbg: 319 print >> sys.stderr, "PyMailPOP3Service connect" 320 321 self.connectioncontext = xConnectionContext 322 server = xConnectionContext.getValueByName("ServerName") 323 if dbg: 324 print >> sys.stderr, server 325 port = xConnectionContext.getValueByName("Port") 326 if dbg: 327 print >> sys.stderr, port 328 connectiontype = xConnectionContext.getValueByName("ConnectionType") 329 if dbg: 330 print >> sys.stderr, connectiontype 331 print >> sys.stderr, "BEFORE" 332 if connectiontype == 'Ssl': 333 self.server = poplib.POP3_SSL(server, port) 334 else: 335 self.server = poplib.POP3(server, port) 336 print >> sys.stderr, "AFTER" 337 338 user = xAuthenticator.getUserName().encode('ascii') 339 password = xAuthenticator.getPassword().encode('ascii') 340 if dbg: 341 print >> sys.stderr, 'Logging in, username of', user 342 self.server.user(user) 343 self.server.pass_(user, password) 344 345 for listener in self.listeners: 346 listener.connected(self.notify) 347 def disconnect(self): 348 if dbg: 349 print >> sys.stderr, "PyMailPOP3Service disconnect" 350 if self.server: 351 self.server.quit() 352 self.server = None 353 for listener in self.listeners: 354 listener.disconnected(self.notify) 355 def isConnected(self): 356 if dbg: 357 print >> sys.stderr, "PyMailPOP3Service isConnected" 358 return self.server != None 359 def getCurrentConnectionContext(self): 360 if dbg: 361 print >> sys.stderr, "PyMailPOP3Service getCurrentConnectionContext" 362 return self.connectioncontext 363 364class PyMailServiceProvider(unohelper.Base, XMailServiceProvider): 365 def __init__( self, ctx ): 366 if dbg: 367 print >> sys.stderr, "PyMailServiceProvider init" 368 self.ctx = ctx 369 def create(self, aType): 370 if dbg: 371 print >> sys.stderr, "PyMailServiceProvider create with", aType 372 if aType == SMTP: 373 return PyMailSMTPService(self.ctx); 374 elif aType == POP3: 375 return PyMailPOP3Service(self.ctx); 376 elif aType == IMAP: 377 return PyMailIMAPService(self.ctx); 378 else: 379 print >> sys.stderr, "PyMailServiceProvider, unknown TYPE", aType 380 381class PyMailMessage(unohelper.Base, XMailMessage): 382 def __init__( self, ctx, sTo='', sFrom='', Subject='', Body=None, aMailAttachment=None ): 383 if dbg: 384 print >> sys.stderr, "PyMailMessage init" 385 self.ctx = ctx 386 387 self.recipients = sTo, 388 self.ccrecipients = () 389 self.bccrecipients = () 390 self.aMailAttachments = () 391 if aMailAttachment != None: 392 self.aMailAttachments = aMailAttachment, 393 394 self.SenderName, self.SenderAddress = parseaddr(sFrom) 395 self.ReplyToAddress = sFrom 396 self.Subject = Subject 397 self.Body = Body 398 if dbg: 399 print >> sys.stderr, "post PyMailMessage init" 400 def addRecipient( self, recipient ): 401 if dbg: 402 print >> sys.stderr, "PyMailMessage.addRecipient", recipient 403 self.recipients = self.recipients, recipient 404 def addCcRecipient( self, ccrecipient ): 405 if dbg: 406 print >> sys.stderr, "PyMailMessage.addCcRecipient", ccrecipient 407 self.ccrecipients = self.ccrecipients, ccrecipient 408 def addBccRecipient( self, bccrecipient ): 409 if dbg: 410 print >> sys.stderr, "PyMailMessage.addBccRecipient", bccrecipient 411 self.bccrecipients = self.bccrecipients, bccrecipient 412 def getRecipients( self ): 413 if dbg: 414 print >> sys.stderr, "PyMailMessage.getRecipients", self.recipients 415 return self.recipients 416 def getCcRecipients( self ): 417 if dbg: 418 print >> sys.stderr, "PyMailMessage.getCcRecipients", self.ccrecipients 419 return self.ccrecipients 420 def getBccRecipients( self ): 421 if dbg: 422 print >> sys.stderr, "PyMailMessage.getBccRecipients", self.bccrecipients 423 return self.bccrecipients 424 def addAttachment( self, aMailAttachment ): 425 if dbg: 426 print >> sys.stderr, "PyMailMessage.addAttachment" 427 self.aMailAttachments = self.aMailAttachments, aMailAttachment 428 def getAttachments( self ): 429 if dbg: 430 print >> sys.stderr, "PyMailMessage.getAttachments" 431 return self.aMailAttachments 432 433# pythonloader looks for a static g_ImplementationHelper variable 434g_ImplementationHelper = unohelper.ImplementationHelper() 435g_ImplementationHelper.addImplementation( \ 436 PyMailServiceProvider, "org.openoffice.pyuno.MailServiceProvider", 437 ("com.sun.star.mail.MailServiceProvider",),) 438g_ImplementationHelper.addImplementation( \ 439 PyMailMessage, "org.openoffice.pyuno.MailMessage", 440 ("com.sun.star.mail.MailMessage",),) 441