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 connectiontype = xConnectionContext.getValueByName("ConnectionType") 115 if connectiontype.upper() == "SSL": 116 if not hasattr(smtplib, "SMTP_SSL"): 117 raise IllegalArgumentException("Connection type is not supported: " + connectiontype, self, 1) 118 self.server = smtplib.SMTP_SSL(server, port, timeout=tout) 119 else: 120 self.server = smtplib.SMTP(server, port,timeout=tout) 121 if dbg: 122 self.server.set_debuglevel(1) 123 124 if dbg: 125 out.write("ConnectionType: %s\n" % str(connectiontype)) 126 127 if connectiontype.upper() == 'INSECURE': 128 self.server.ehlo() 129 self.server.starttls() 130 self.server.ehlo() 131 132 user = xAuthenticator.getUserName().encode('ascii') 133 password = xAuthenticator.getPassword().encode('ascii') 134 if user != '': 135 if dbg: 136 out.write('Logging in, username of %s\n' % user) 137 self.server.login(user, password) 138 139 for listener in self.listeners: 140 listener.connected(self.notify) 141 def disconnect(self): 142 if dbg: 143 out.write("PyMailSMTPService disconnect\n") 144 if self.server: 145 self.server.quit() 146 self.server = None 147 for listener in self.listeners: 148 listener.disconnected(self.notify) 149 def isConnected(self): 150 if dbg: 151 out.write("PyMailSMTPService isConnected\n") 152 return self.server != None 153 def getCurrentConnectionContext(self): 154 if dbg: 155 out.write("PyMailSMTPService getCurrentConnectionContext\n") 156 return self.connectioncontext 157 def sendMailMessage(self, xMailMessage): 158 COMMASPACE = ', ' 159 160 if dbg: 161 out.write("PyMailSMTPService sendMailMessage\n") 162 recipients = xMailMessage.getRecipients() 163 sendermail = xMailMessage.SenderAddress 164 sendername = xMailMessage.SenderName 165 subject = xMailMessage.Subject 166 ccrecipients = xMailMessage.getCcRecipients() 167 bccrecipients = xMailMessage.getBccRecipients() 168 if dbg: 169 out.write("PyMailSMTPService subject %s\n" % subject) 170 out.write("PyMailSMTPService from %s\n" % sendername.encode('utf-8')) 171 out.write("PyMailSMTPService from %s\n" % sendermail) 172 out.write("PyMailSMTPService send to %s\n" % str(recipients)) 173 174 attachments = xMailMessage.getAttachments() 175 176 textmsg = Message() 177 178 content = xMailMessage.Body 179 flavors = content.getTransferDataFlavors() 180 if dbg: 181 out.write("PyMailSMTPService flavors len %d\n" % len(flavors)) 182 183 #Use first flavor that's sane for an email body 184 for flavor in flavors: 185 if flavor.MimeType.find('text/html') != -1 or flavor.MimeType.find('text/plain') != -1: 186 if dbg: 187 out.write("PyMailSMTPService mimetype is %s\n" % flavor.MimeType) 188 textbody = content.getTransferData(flavor) 189 try: 190 textbody = textbody.value 191 except: 192 pass 193 textbody = textbody.encode('utf-8') 194 195 if len(textbody): 196 mimeEncoding = re.sub("charset=.*", "charset=UTF-8", flavor.MimeType) 197 if mimeEncoding.find('charset=UTF-8') == -1: 198 mimeEncoding = mimeEncoding + "; charset=UTF-8" 199 textmsg['Content-Type'] = mimeEncoding 200 textmsg['MIME-Version'] = '1.0' 201 textmsg.set_payload(textbody) 202 203 break 204 205 if (len(attachments)): 206 msg = MIMEMultipart() 207 msg.epilogue = '' 208 msg.attach(textmsg) 209 else: 210 msg = textmsg 211 212 hdr = Header(sendername, 'utf-8') 213 hdr.append('<'+sendermail+'>','us-ascii') 214 msg['Subject'] = subject 215 msg['From'] = hdr 216 msg['To'] = COMMASPACE.join(recipients) 217 if len(ccrecipients): 218 msg['Cc'] = COMMASPACE.join(ccrecipients) 219 if xMailMessage.ReplyToAddress != '': 220 msg['Reply-To'] = xMailMessage.ReplyToAddress 221 222 mailerstring = "OpenOffice via Caolan's mailmerge component" 223 try: 224 ctx = uno.getComponentContext() 225 aConfigProvider = ctx.ServiceManager.createInstance("com.sun.star.configuration.ConfigurationProvider") 226 prop = uno.createUnoStruct('com.sun.star.beans.PropertyValue') 227 prop.Name = "nodepath" 228 prop.Value = "/org.openoffice.Setup/Product" 229 aSettings = aConfigProvider.createInstanceWithArguments("com.sun.star.configuration.ConfigurationAccess", 230 (prop,)) 231 mailerstring = aSettings.getByName("ooName") + " " + \ 232 aSettings.getByName("ooSetupVersion") + " via Caolan's mailmerge component" 233 except: 234 pass 235 236 msg['X-Mailer'] = mailerstring 237 msg['Date'] = formatdate(localtime=True) 238 239 for attachment in attachments: 240 content = attachment.Data 241 flavors = content.getTransferDataFlavors() 242 flavor = flavors[0] 243 ctype = flavor.MimeType 244 maintype, subtype = ctype.split('/', 1) 245 msgattachment = MIMEBase(maintype, subtype) 246 data = content.getTransferData(flavor) 247 msgattachment.set_payload(data) 248 Encoders.encode_base64(msgattachment) 249 fname = attachment.ReadableName 250 try: 251 fname.encode('ascii') 252 except: 253 fname = ('utf-8','',fname.encode('utf-8')) 254 msgattachment.add_header('Content-Disposition', 'attachment', \ 255 filename=fname) 256 msg.attach(msgattachment) 257 258 uniquer = {} 259 for key in recipients: 260 uniquer[key] = True 261 if len(ccrecipients): 262 for key in ccrecipients: 263 uniquer[key] = True 264 if len(bccrecipients): 265 for key in bccrecipients: 266 uniquer[key] = True 267 truerecipients = list(uniquer.keys()) 268 269 if dbg: 270 out.write("PyMailSMTPService recipients are %s\n" % str(truerecipients)) 271 272 self.server.sendmail(sendermail, truerecipients, msg.as_string()) 273 274class PyMailIMAPService(unohelper.Base, XMailService): 275 def __init__( self, ctx ): 276 self.ctx = ctx 277 self.listeners = [] 278 self.supportedtypes = ('Insecure', 'Ssl') 279 self.server = None 280 self.connectioncontext = None 281 self.notify = EventObject(self) 282 if dbg: 283 out.write("PyMailIMAPService init\n") 284 def addConnectionListener(self, xListener): 285 if dbg: 286 out.write("PyMailIMAPService addConnectionListener\n") 287 self.listeners.append(xListener) 288 def removeConnectionListener(self, xListener): 289 if dbg: 290 out.write("PyMailIMAPService removeConnectionListener\n") 291 self.listeners.remove(xListener) 292 def getSupportedConnectionTypes(self): 293 if dbg: 294 out.write("PyMailIMAPService getSupportedConnectionTypes\n") 295 return self.supportedtypes 296 def connect(self, xConnectionContext, xAuthenticator): 297 if dbg: 298 out.write("PyMailIMAPService connect\n") 299 300 self.connectioncontext = xConnectionContext 301 server = xConnectionContext.getValueByName("ServerName") 302 if dbg: 303 out.write("Server: %s\n" % server) 304 port = xConnectionContext.getValueByName("Port") 305 if dbg: 306 out.write("Port: %d\n" % port) 307 connectiontype = xConnectionContext.getValueByName("ConnectionType") 308 if dbg: 309 out.write("Connection type: %s\n" % connectiontype) 310 out.write("BEFORE\n") 311 if connectiontype.upper() == 'SSL': 312 self.server = imaplib.IMAP4_SSL(server, port) 313 else: 314 self.server = imaplib.IMAP4(server, port) 315 out.write("AFTER\n") 316 317 user = xAuthenticator.getUserName().encode('ascii') 318 password = xAuthenticator.getPassword().encode('ascii') 319 if user != '': 320 if dbg: 321 out.write('Logging in, username of %s\n' % user) 322 self.server.login(user, password) 323 324 for listener in self.listeners: 325 listener.connected(self.notify) 326 def disconnect(self): 327 if dbg: 328 out.write("PyMailIMAPService disconnect\n") 329 if self.server: 330 self.server.logout() 331 self.server = None 332 for listener in self.listeners: 333 listener.disconnected(self.notify) 334 def isConnected(self): 335 if dbg: 336 out.write("PyMailIMAPService isConnected\n") 337 return self.server != None 338 def getCurrentConnectionContext(self): 339 if dbg: 340 out.write("PyMailIMAPService getCurrentConnectionContext\n") 341 return self.connectioncontext 342 343class PyMailPOP3Service(unohelper.Base, XMailService): 344 def __init__( self, ctx ): 345 self.ctx = ctx 346 self.listeners = [] 347 self.supportedtypes = ('Insecure', 'Ssl') 348 self.server = None 349 self.connectioncontext = None 350 self.notify = EventObject(self) 351 if dbg: 352 out.write("PyMailPOP3Service init\n") 353 def addConnectionListener(self, xListener): 354 if dbg: 355 out.write("PyMailPOP3Service addConnectionListener\n") 356 self.listeners.append(xListener) 357 def removeConnectionListener(self, xListener): 358 if dbg: 359 out.write("PyMailPOP3Service removeConnectionListener\n") 360 self.listeners.remove(xListener) 361 def getSupportedConnectionTypes(self): 362 if dbg: 363 out.write("PyMailPOP3Service getSupportedConnectionTypes\n") 364 return self.supportedtypes 365 def connect(self, xConnectionContext, xAuthenticator): 366 if dbg: 367 out.write("PyMailPOP3Service connect\n") 368 369 self.connectioncontext = xConnectionContext 370 server = xConnectionContext.getValueByName("ServerName") 371 if dbg: 372 out.write("Server: %s\n" % server) 373 port = xConnectionContext.getValueByName("Port") 374 if dbg: 375 out.write("Port: %s\n" % port) 376 connectiontype = xConnectionContext.getValueByName("ConnectionType") 377 if dbg: 378 out.write("Connection type: %s\n" % str(connectiontype)) 379 out.write("BEFORE\n") 380 if connectiontype.upper() == 'SSL': 381 self.server = poplib.POP3_SSL(server, port) 382 else: 383 tout = xConnectionContext.getValueByName("Timeout") 384 if dbg: 385 out.write("Timeout is instance of int? %s\n" % isinstance(tout,int)) 386 if not isinstance(tout,int): 387 tout = _GLOBAL_DEFAULT_TIMEOUT 388 if dbg: 389 out.write("Timeout: %s\n" % str(tout)) 390 self.server = poplib.POP3(server, port, timeout=tout) 391 out.write("AFTER\n") 392 393 user = xAuthenticator.getUserName().encode('ascii') 394 password = xAuthenticator.getPassword().encode('ascii') 395 if dbg: 396 out.write('Logging in, username of %s\n' % user) 397 self.server.user(user) 398 self.server.pass_(password) 399 400 for listener in self.listeners: 401 listener.connected(self.notify) 402 def disconnect(self): 403 if dbg: 404 out.write("PyMailPOP3Service disconnect\n") 405 if self.server: 406 self.server.quit() 407 self.server = None 408 for listener in self.listeners: 409 listener.disconnected(self.notify) 410 def isConnected(self): 411 if dbg: 412 out.write("PyMailPOP3Service isConnected\n") 413 return self.server != None 414 def getCurrentConnectionContext(self): 415 if dbg: 416 out.write("PyMailPOP3Service getCurrentConnectionContext\n") 417 return self.connectioncontext 418 419class PyMailServiceProvider(unohelper.Base, XMailServiceProvider): 420 def __init__( self, ctx ): 421 if dbg: 422 out.write("PyMailServiceProvider init\n") 423 self.ctx = ctx 424 def create(self, aType): 425 if dbg: 426 out.write("PyMailServiceProvider create with %s\n" % aType) 427 if aType == SMTP: 428 return PyMailSMTPService(self.ctx); 429 elif aType == POP3: 430 return PyMailPOP3Service(self.ctx); 431 elif aType == IMAP: 432 return PyMailIMAPService(self.ctx); 433 else: 434 out.write("PyMailServiceProvider, unknown TYPE %s\n" % aType) 435 436class PyMailMessage(unohelper.Base, XMailMessage): 437 def __init__( self, ctx, sTo='', sFrom='', Subject='', Body=None, aMailAttachment=None ): 438 if dbg: 439 out.write("PyMailMessage init\n") 440 self.ctx = ctx 441 442 self.recipients = [sTo] 443 self.ccrecipients = [] 444 self.bccrecipients = [] 445 self.aMailAttachments = [] 446 if aMailAttachment != None: 447 self.aMailAttachments.append(aMailAttachment) 448 449 self.SenderName, self.SenderAddress = parseaddr(sFrom) 450 self.ReplyToAddress = sFrom 451 self.Subject = Subject 452 self.Body = Body 453 if dbg: 454 out.write("post PyMailMessage init\n") 455 def addRecipient( self, recipient ): 456 if dbg: 457 out.write("PyMailMessage.addRecipient%s\n" % recipient) 458 self.recipients.append(recipient) 459 def addCcRecipient( self, ccrecipient ): 460 if dbg: 461 out.write("PyMailMessage.addCcRecipient%s\n" % ccrecipient) 462 self.ccrecipients.append(ccrecipient) 463 def addBccRecipient( self, bccrecipient ): 464 if dbg: 465 out.write("PyMailMessage.addBccRecipient%s\n" % bccrecipient) 466 self.bccrecipients.append(bccrecipient) 467 def getRecipients( self ): 468 if dbg: 469 out.write("PyMailMessage.getRecipients%s\n" % self.recipients) 470 return tuple(self.recipients) 471 def getCcRecipients( self ): 472 if dbg: 473 out.write("PyMailMessage.getCcRecipients%s\n" % self.ccrecipients) 474 return tuple(self.ccrecipients) 475 def getBccRecipients( self ): 476 if dbg: 477 out.write("PyMailMessage.getBccRecipients%s\n" % self.bccrecipients) 478 return tuple(self.bccrecipients) 479 def addAttachment( self, aMailAttachment ): 480 if dbg: 481 out.write("PyMailMessage.addAttachment\n") 482 self.aMailAttachments.append(aMailAttachment) 483 def getAttachments( self ): 484 if dbg: 485 out.write("PyMailMessage.getAttachments\n") 486 return tuple(self.aMailAttachments) 487 488 489# pythonloader looks for a static g_ImplementationHelper variable 490g_ImplementationHelper = unohelper.ImplementationHelper() 491g_ImplementationHelper.addImplementation( \ 492 PyMailServiceProvider, "org.openoffice.pyuno.MailServiceProvider", 493 ("com.sun.star.mail.MailServiceProvider",),) 494g_ImplementationHelper.addImplementation( \ 495 PyMailMessage, "org.openoffice.pyuno.MailMessage", 496 ("com.sun.star.mail.MailMessage",),) 497