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