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