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