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(self) 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.upper() == '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 fname = attachment.ReadableName 209 try: 210 fname.encode('ascii') 211 except: 212 fname = ('utf-8','',fname.encode('utf-8')) 213 msgattachment.add_header('Content-Disposition', 'attachment', \ 214 filename=fname) 215 msg.attach(msgattachment) 216 217 218 uniquer = {} 219 for key in recipients: 220 uniquer[key] = True 221 if len(ccrecipients): 222 for key in ccrecipients: 223 uniquer[key] = True 224 if len(bccrecipients): 225 for key in bccrecipients: 226 uniquer[key] = True 227 truerecipients = uniquer.keys() 228 229 if dbg: 230 print >> sys.stderr, "PyMailSMPTService recipients are", truerecipients 231 232 self.server.sendmail(sendermail, truerecipients, msg.as_string()) 233 234class PyMailIMAPService(unohelper.Base, XMailService): 235 def __init__( self, ctx ): 236 self.ctx = ctx 237 self.listeners = [] 238 self.supportedtypes = ('Insecure', 'Ssl') 239 self.server = None 240 self.connectioncontext = None 241 self.notify = EventObject(self) 242 if dbg: 243 print >> sys.stderr, "PyMailIMAPService init" 244 def addConnectionListener(self, xListener): 245 if dbg: 246 print >> sys.stderr, "PyMailIMAPService addConnectionListener" 247 self.listeners.append(xListener) 248 def removeConnectionListener(self, xListener): 249 if dbg: 250 print >> sys.stderr, "PyMailIMAPService removeConnectionListener" 251 self.listeners.remove(xListener) 252 def getSupportedConnectionTypes(self): 253 if dbg: 254 print >> sys.stderr, "PyMailIMAPService getSupportedConnectionTypes" 255 return self.supportedtypes 256 def connect(self, xConnectionContext, xAuthenticator): 257 if dbg: 258 print >> sys.stderr, "PyMailIMAPService connect" 259 260 self.connectioncontext = xConnectionContext 261 server = xConnectionContext.getValueByName("ServerName") 262 if dbg: 263 print >> sys.stderr, server 264 port = xConnectionContext.getValueByName("Port") 265 if dbg: 266 print >> sys.stderr, port 267 connectiontype = xConnectionContext.getValueByName("ConnectionType") 268 if dbg: 269 print >> sys.stderr, connectiontype 270 print >> sys.stderr, "BEFORE" 271 if connectiontype.upper() == 'SSL': 272 self.server = imaplib.IMAP4_SSL(server, port) 273 else: 274 self.server = imaplib.IMAP4(server, port) 275 print >> sys.stderr, "AFTER" 276 277 user = xAuthenticator.getUserName().encode('ascii') 278 password = xAuthenticator.getPassword().encode('ascii') 279 if user != '': 280 if dbg: 281 print >> sys.stderr, 'Logging in, username of', user 282 self.server.login(user, password) 283 284 for listener in self.listeners: 285 listener.connected(self.notify) 286 def disconnect(self): 287 if dbg: 288 print >> sys.stderr, "PyMailIMAPService disconnect" 289 if self.server: 290 self.server.logout() 291 self.server = None 292 for listener in self.listeners: 293 listener.disconnected(self.notify) 294 def isConnected(self): 295 if dbg: 296 print >> sys.stderr, "PyMailIMAPService isConnected" 297 return self.server != None 298 def getCurrentConnectionContext(self): 299 if dbg: 300 print >> sys.stderr, "PyMailIMAPService getCurrentConnectionContext" 301 return self.connectioncontext 302 303class PyMailPOP3Service(unohelper.Base, XMailService): 304 def __init__( self, ctx ): 305 self.ctx = ctx 306 self.listeners = [] 307 self.supportedtypes = ('Insecure', 'Ssl') 308 self.server = None 309 self.connectioncontext = None 310 self.notify = EventObject(self) 311 if dbg: 312 print >> sys.stderr, "PyMailPOP3Service init" 313 def addConnectionListener(self, xListener): 314 if dbg: 315 print >> sys.stderr, "PyMailPOP3Service addConnectionListener" 316 self.listeners.append(xListener) 317 def removeConnectionListener(self, xListener): 318 if dbg: 319 print >> sys.stderr, "PyMailPOP3Service removeConnectionListener" 320 self.listeners.remove(xListener) 321 def getSupportedConnectionTypes(self): 322 if dbg: 323 print >> sys.stderr, "PyMailPOP3Service getSupportedConnectionTypes" 324 return self.supportedtypes 325 def connect(self, xConnectionContext, xAuthenticator): 326 if dbg: 327 print >> sys.stderr, "PyMailPOP3Service connect" 328 329 self.connectioncontext = xConnectionContext 330 server = xConnectionContext.getValueByName("ServerName") 331 if dbg: 332 print >> sys.stderr, server 333 port = xConnectionContext.getValueByName("Port") 334 if dbg: 335 print >> sys.stderr, port 336 connectiontype = xConnectionContext.getValueByName("ConnectionType") 337 if dbg: 338 print >> sys.stderr, connectiontype 339 print >> sys.stderr, "BEFORE" 340 if connectiontype.upper() == 'SSL': 341 self.server = poplib.POP3_SSL(server, port) 342 else: 343 self.server = poplib.POP3(server, port) 344 print >> sys.stderr, "AFTER" 345 346 user = xAuthenticator.getUserName().encode('ascii') 347 password = xAuthenticator.getPassword().encode('ascii') 348 if dbg: 349 print >> sys.stderr, 'Logging in, username of', user 350 self.server.user(user) 351 self.server.pass_(password) 352 353 for listener in self.listeners: 354 listener.connected(self.notify) 355 def disconnect(self): 356 if dbg: 357 print >> sys.stderr, "PyMailPOP3Service disconnect" 358 if self.server: 359 self.server.quit() 360 self.server = None 361 for listener in self.listeners: 362 listener.disconnected(self.notify) 363 def isConnected(self): 364 if dbg: 365 print >> sys.stderr, "PyMailPOP3Service isConnected" 366 return self.server != None 367 def getCurrentConnectionContext(self): 368 if dbg: 369 print >> sys.stderr, "PyMailPOP3Service getCurrentConnectionContext" 370 return self.connectioncontext 371 372class PyMailServiceProvider(unohelper.Base, XMailServiceProvider): 373 def __init__( self, ctx ): 374 if dbg: 375 print >> sys.stderr, "PyMailServiceProvider init" 376 self.ctx = ctx 377 def create(self, aType): 378 if dbg: 379 print >> sys.stderr, "PyMailServiceProvider create with", aType 380 if aType == SMTP: 381 return PyMailSMTPService(self.ctx); 382 elif aType == POP3: 383 return PyMailPOP3Service(self.ctx); 384 elif aType == IMAP: 385 return PyMailIMAPService(self.ctx); 386 else: 387 print >> sys.stderr, "PyMailServiceProvider, unknown TYPE", aType 388 389class PyMailMessage(unohelper.Base, XMailMessage): 390 def __init__( self, ctx, sTo='', sFrom='', Subject='', Body=None, aMailAttachment=None ): 391 if dbg: 392 print >> sys.stderr, "PyMailMessage init" 393 self.ctx = ctx 394 395 self.recipients = [sTo] 396 self.ccrecipients = [] 397 self.bccrecipients = [] 398 self.aMailAttachments = [] 399 if aMailAttachment != None: 400 self.aMailAttachments.append(aMailAttachment) 401 402 self.SenderName, self.SenderAddress = parseaddr(sFrom) 403 self.ReplyToAddress = sFrom 404 self.Subject = Subject 405 self.Body = Body 406 if dbg: 407 print >> sys.stderr, "post PyMailMessage init" 408 def addRecipient( self, recipient ): 409 if dbg: 410 print >> sys.stderr, "PyMailMessage.addRecipient", recipient 411 self.recipients.append(recipient) 412 def addCcRecipient( self, ccrecipient ): 413 if dbg: 414 print >> sys.stderr, "PyMailMessage.addCcRecipient", ccrecipient 415 self.ccrecipients.append(ccrecipient) 416 def addBccRecipient( self, bccrecipient ): 417 if dbg: 418 print >> sys.stderr, "PyMailMessage.addBccRecipient", bccrecipient 419 self.bccrecipients.append(bccrecipient) 420 def getRecipients( self ): 421 if dbg: 422 print >> sys.stderr, "PyMailMessage.getRecipients", self.recipients 423 return tuple(self.recipients) 424 def getCcRecipients( self ): 425 if dbg: 426 print >> sys.stderr, "PyMailMessage.getCcRecipients", self.ccrecipients 427 return tuple(self.ccrecipients) 428 def getBccRecipients( self ): 429 if dbg: 430 print >> sys.stderr, "PyMailMessage.getBccRecipients", self.bccrecipients 431 return tuple(self.bccrecipients) 432 def addAttachment( self, aMailAttachment ): 433 if dbg: 434 print >> sys.stderr, "PyMailMessage.addAttachment" 435 self.aMailAttachments.append(aMailAttachment) 436 def getAttachments( self ): 437 if dbg: 438 print >> sys.stderr, "PyMailMessage.getAttachments" 439 return tuple(self.aMailAttachments) 440 441 442# pythonloader looks for a static g_ImplementationHelper variable 443g_ImplementationHelper = unohelper.ImplementationHelper() 444g_ImplementationHelper.addImplementation( \ 445 PyMailServiceProvider, "org.openoffice.pyuno.MailServiceProvider", 446 ("com.sun.star.mail.MailServiceProvider",),) 447g_ImplementationHelper.addImplementation( \ 448 PyMailMessage, "org.openoffice.pyuno.MailMessage", 449 ("com.sun.star.mail.MailMessage",),) 450