1 # Caolan McNamara caolanm@redhat.com
2 # a simple email mailmerge component
4 # manual installation for hackers, not necessary for users
5 # cp mailmerge.py /usr/lib/libreoffice/program
6 # cd /usr/lib/libreoffice/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">
20 #to implement com::sun::star::mail::XMailServiceProvider
22 #to implement com.sun.star.mail.XMailMessage
24 from com
.sun
.star
.mail
import XMailServiceProvider
25 from com
.sun
.star
.mail
import XMailService
26 from com
.sun
.star
.mail
import XSmtpService
27 from com
.sun
.star
.mail
import XConnectionListener
28 from com
.sun
.star
.mail
import XAuthenticator
29 from com
.sun
.star
.mail
import XMailMessage
30 from com
.sun
.star
.mail
.MailServiceType
import SMTP
31 from com
.sun
.star
.mail
.MailServiceType
import POP3
32 from com
.sun
.star
.mail
.MailServiceType
import IMAP
33 from com
.sun
.star
.uno
import XCurrentContext
34 from com
.sun
.star
.lang
import IllegalArgumentException
35 from com
.sun
.star
.lang
import EventObject
36 from com
.sun
.star
.lang
import XServiceInfo
37 from com
.sun
.star
.mail
import SendMailMessageFailedException
39 from email
.mime
.base
import MIMEBase
40 from email
.message
import Message
41 from email
.charset
import Charset
42 from email
.charset
import QP
43 from email
.encoders
import encode_base64
44 from email
.header
import Header
45 from email
.mime
.multipart
import MIMEMultipart
46 from email
.utils
import formatdate
47 from email
.utils
import parseaddr
48 from socket
import _GLOBAL_DEFAULT_TIMEOUT
50 import sys
, ssl
, smtplib
, imaplib
, poplib
53 # pythonloader looks for a static g_ImplementationHelper variable
54 g_ImplementationHelper
= unohelper
.ImplementationHelper()
55 g_providerImplName
= "org.openoffice.pyuno.MailServiceProvider"
56 g_messageImplName
= "org.openoffice.pyuno.MailMessage"
58 class PyMailSMTPService(unohelper
.Base
, XSmtpService
):
59 def __init__( self
, ctx
):
62 self
.supportedtypes
= ('Insecure', 'Ssl')
64 self
.connectioncontext
= None
65 self
.notify
= EventObject(self
)
67 print("PyMailSMTPService init", file=sys
.stderr
)
68 print("python version is: " + sys
.version
, file=sys
.stderr
)
69 def addConnectionListener(self
, xListener
):
71 print("PyMailSMTPService addConnectionListener", file=sys
.stderr
)
72 self
.listeners
.append(xListener
)
73 def removeConnectionListener(self
, xListener
):
75 print("PyMailSMTPService removeConnectionListener", file=sys
.stderr
)
76 self
.listeners
.remove(xListener
)
77 def getSupportedConnectionTypes(self
):
79 print("PyMailSMTPService getSupportedConnectionTypes", file=sys
.stderr
)
80 return self
.supportedtypes
81 def connect(self
, xConnectionContext
, xAuthenticator
):
82 self
.connectioncontext
= xConnectionContext
84 print("PyMailSMTPService connect", file=sys
.stderr
)
85 server
= xConnectionContext
.getValueByName("ServerName").strip()
87 print("ServerName: " + server
, file=sys
.stderr
)
88 port
= int(xConnectionContext
.getValueByName("Port"))
90 print("Port: " + str(port
), file=sys
.stderr
)
91 tout
= xConnectionContext
.getValueByName("Timeout")
93 print(isinstance(tout
,int), file=sys
.stderr
)
94 if not isinstance(tout
,int):
95 tout
= _GLOBAL_DEFAULT_TIMEOUT
97 print("Timeout: " + str(tout
), file=sys
.stderr
)
99 self
.server
= smtplib
.SMTP_SSL(server
, port
, timeout
=tout
, context
=ssl
.create_default_context())
101 self
.server
= smtplib
.SMTP(server
, port
,timeout
=tout
)
104 self
.server
.set_debuglevel(1)
106 connectiontype
= xConnectionContext
.getValueByName("ConnectionType")
108 print("ConnectionType: " + connectiontype
, file=sys
.stderr
)
109 if connectiontype
.upper() == 'SSL' and port
!= 465:
111 self
.server
.starttls(context
=ssl
.create_default_context())
114 user
= xAuthenticator
.getUserName()
115 password
= xAuthenticator
.getPassword()
118 print("Logging in, username of: " + user
, file=sys
.stderr
)
119 self
.server
.login(user
, password
)
121 for listener
in self
.listeners
:
122 listener
.connected(self
.notify
)
123 def disconnect(self
):
125 print("PyMailSMTPService disconnect", file=sys
.stderr
)
129 for listener
in self
.listeners
:
130 listener
.disconnected(self
.notify
)
131 def isConnected(self
):
133 print("PyMailSMTPService isConnected", file=sys
.stderr
)
134 return self
.server
!= None
135 def getCurrentConnectionContext(self
):
137 print("PyMailSMTPService getCurrentConnectionContext", file=sys
.stderr
)
138 return self
.connectioncontext
139 def sendMailMessage(self
, xMailMessage
):
143 print("PyMailSMTPService sendMailMessage", file=sys
.stderr
)
144 recipients
= xMailMessage
.getRecipients()
145 sendermail
= xMailMessage
.SenderAddress
146 sendername
= xMailMessage
.SenderName
147 subject
= xMailMessage
.Subject
148 ccrecipients
= xMailMessage
.getCcRecipients()
149 bccrecipients
= xMailMessage
.getBccRecipients()
151 print("PyMailSMTPService subject: " + subject
, file=sys
.stderr
)
152 print("PyMailSMTPService from: " + sendername
, file=sys
.stderr
)
153 print("PyMailSMTPService from: " + sendermail
, file=sys
.stderr
)
154 print("PyMailSMTPService send to: %s" % (recipients
,), file=sys
.stderr
)
156 attachments
= xMailMessage
.getAttachments()
160 content
= xMailMessage
.Body
161 flavors
= content
.getTransferDataFlavors()
163 print("PyMailSMTPService flavors len: %d" % (len(flavors
),), file=sys
.stderr
)
165 #Use first flavor that's sane for an email body
166 for flavor
in flavors
:
167 if flavor
.MimeType
.find('text/html') != -1 or flavor
.MimeType
.find('text/plain') != -1:
169 print("PyMailSMTPService mimetype is: " + flavor
.MimeType
, file=sys
.stderr
)
170 textbody
= content
.getTransferData(flavor
)
173 mimeEncoding
= re
.sub("charset=.*", "charset=UTF-8", flavor
.MimeType
)
174 if mimeEncoding
.find('charset=UTF-8') == -1:
175 mimeEncoding
= mimeEncoding
+ "; charset=UTF-8"
176 textmsg
['Content-Type'] = mimeEncoding
177 textmsg
['MIME-Version'] = '1.0'
180 #it's a string, get it as utf-8 bytes
181 textbody
= textbody
.encode('utf-8')
183 #it's a bytesequence, get raw bytes
184 textbody
= textbody
.value
185 textbody
= textbody
.decode('utf-8')
188 textmsg
.set_payload(textbody
, c
)
192 if (len(attachments
)):
193 msg
= MIMEMultipart()
199 hdr
= Header(sendername
, 'utf-8')
200 hdr
.append('<'+sendermail
+'>','us-ascii')
201 msg
['Subject'] = subject
203 msg
['To'] = COMMASPACE
.join(recipients
)
204 if len(ccrecipients
):
205 msg
['Cc'] = COMMASPACE
.join(ccrecipients
)
206 if xMailMessage
.ReplyToAddress
!= '':
207 msg
['Reply-To'] = xMailMessage
.ReplyToAddress
209 mailerstring
= "LibreOffice via Caolan's mailmerge component"
211 ctx
= uno
.getComponentContext()
212 aConfigProvider
= ctx
.ServiceManager
.createInstance("com.sun.star.configuration.ConfigurationProvider")
213 prop
= uno
.createUnoStruct('com.sun.star.beans.PropertyValue')
214 prop
.Name
= "nodepath"
215 prop
.Value
= "/org.openoffice.Setup/Product"
216 aSettings
= aConfigProvider
.createInstanceWithArguments("com.sun.star.configuration.ConfigurationAccess",
218 mailerstring
= aSettings
.getByName("ooName") + " " + \
219 aSettings
.getByName("ooSetupVersion") + " via Caolan's mailmerge component"
223 msg
['X-Mailer'] = mailerstring
224 msg
['Date'] = formatdate(localtime
=True)
226 for attachment
in attachments
:
227 content
= attachment
.Data
228 flavors
= content
.getTransferDataFlavors()
230 ctype
= flavor
.MimeType
231 maintype
, subtype
= ctype
.split('/', 1)
232 msgattachment
= MIMEBase(maintype
, subtype
)
233 data
= content
.getTransferData(flavor
)
234 msgattachment
.set_payload(data
.value
)
235 encode_base64(msgattachment
)
236 fname
= attachment
.ReadableName
238 msgattachment
.add_header('Content-Disposition', 'attachment', \
241 msgattachment
.add_header('Content-Disposition', 'attachment', \
242 filename
=('utf-8','',fname
))
244 print(("PyMailSMTPService attachmentheader: ", str(msgattachment
)), file=sys
.stderr
)
246 msg
.attach(msgattachment
)
249 for key
in recipients
:
251 if len(ccrecipients
):
252 for key
in ccrecipients
:
254 if len(bccrecipients
):
255 for key
in bccrecipients
:
257 truerecipients
= uniquer
.keys()
260 print(("PyMailSMTPService recipients are: ", truerecipients
), file=sys
.stderr
)
262 self
.server
.sendmail(sendermail
, truerecipients
, msg
.as_string())
264 class PyMailIMAPService(unohelper
.Base
, XMailService
):
265 def __init__( self
, ctx
):
268 self
.supportedtypes
= ('Insecure', 'Ssl')
270 self
.connectioncontext
= None
271 self
.notify
= EventObject(self
)
273 print("PyMailIMAPService init", file=sys
.stderr
)
274 def addConnectionListener(self
, xListener
):
276 print("PyMailIMAPService addConnectionListener", file=sys
.stderr
)
277 self
.listeners
.append(xListener
)
278 def removeConnectionListener(self
, xListener
):
280 print("PyMailIMAPService removeConnectionListener", file=sys
.stderr
)
281 self
.listeners
.remove(xListener
)
282 def getSupportedConnectionTypes(self
):
284 print("PyMailIMAPService getSupportedConnectionTypes", file=sys
.stderr
)
285 return self
.supportedtypes
286 def connect(self
, xConnectionContext
, xAuthenticator
):
288 print("PyMailIMAPService connect", file=sys
.stderr
)
290 self
.connectioncontext
= xConnectionContext
291 server
= xConnectionContext
.getValueByName("ServerName")
293 print(server
, file=sys
.stderr
)
294 port
= int(xConnectionContext
.getValueByName("Port"))
296 print(port
, file=sys
.stderr
)
297 connectiontype
= xConnectionContext
.getValueByName("ConnectionType")
299 print(connectiontype
, file=sys
.stderr
)
300 print("BEFORE", file=sys
.stderr
)
301 if connectiontype
.upper() == 'SSL':
302 self
.server
= imaplib
.IMAP4_SSL(server
, port
, ssl_context
=ssl
.create_default_context())
304 self
.server
= imaplib
.IMAP4(server
, port
)
305 print("AFTER", file=sys
.stderr
)
307 user
= xAuthenticator
.getUserName()
308 password
= xAuthenticator
.getPassword()
311 print("Logging in, username of: " + user
, file=sys
.stderr
)
312 self
.server
.login(user
, password
)
314 for listener
in self
.listeners
:
315 listener
.connected(self
.notify
)
316 def disconnect(self
):
318 print("PyMailIMAPService disconnect", file=sys
.stderr
)
322 for listener
in self
.listeners
:
323 listener
.disconnected(self
.notify
)
324 def isConnected(self
):
326 print("PyMailIMAPService isConnected", file=sys
.stderr
)
327 return self
.server
!= None
328 def getCurrentConnectionContext(self
):
330 print("PyMailIMAPService getCurrentConnectionContext", file=sys
.stderr
)
331 return self
.connectioncontext
333 class PyMailPOP3Service(unohelper
.Base
, XMailService
):
334 def __init__( self
, ctx
):
337 self
.supportedtypes
= ('Insecure', 'Ssl')
339 self
.connectioncontext
= None
340 self
.notify
= EventObject(self
)
342 print("PyMailPOP3Service init", file=sys
.stderr
)
343 def addConnectionListener(self
, xListener
):
345 print("PyMailPOP3Service addConnectionListener", file=sys
.stderr
)
346 self
.listeners
.append(xListener
)
347 def removeConnectionListener(self
, xListener
):
349 print("PyMailPOP3Service removeConnectionListener", file=sys
.stderr
)
350 self
.listeners
.remove(xListener
)
351 def getSupportedConnectionTypes(self
):
353 print("PyMailPOP3Service getSupportedConnectionTypes", file=sys
.stderr
)
354 return self
.supportedtypes
355 def connect(self
, xConnectionContext
, xAuthenticator
):
357 print("PyMailPOP3Service connect", file=sys
.stderr
)
359 self
.connectioncontext
= xConnectionContext
360 server
= xConnectionContext
.getValueByName("ServerName")
362 print(server
, file=sys
.stderr
)
363 port
= int(xConnectionContext
.getValueByName("Port"))
365 print(port
, file=sys
.stderr
)
366 connectiontype
= xConnectionContext
.getValueByName("ConnectionType")
368 print(connectiontype
, file=sys
.stderr
)
369 print("BEFORE", file=sys
.stderr
)
370 if connectiontype
.upper() == 'SSL':
371 self
.server
= poplib
.POP3_SSL(server
, port
, context
=ssl
.create_default_context())
373 tout
= xConnectionContext
.getValueByName("Timeout")
375 print(isinstance(tout
,int), file=sys
.stderr
)
376 if not isinstance(tout
,int):
377 tout
= _GLOBAL_DEFAULT_TIMEOUT
379 print("Timeout: " + str(tout
), file=sys
.stderr
)
380 self
.server
= poplib
.POP3(server
, port
, timeout
=tout
)
381 print("AFTER", file=sys
.stderr
)
383 user
= xAuthenticator
.getUserName()
384 password
= xAuthenticator
.getPassword()
386 print("Logging in, username of: " + user
, file=sys
.stderr
)
387 self
.server
.user(user
)
388 self
.server
.pass_(password
)
390 for listener
in self
.listeners
:
391 listener
.connected(self
.notify
)
392 def disconnect(self
):
394 print("PyMailPOP3Service disconnect", file=sys
.stderr
)
398 for listener
in self
.listeners
:
399 listener
.disconnected(self
.notify
)
400 def isConnected(self
):
402 print("PyMailPOP3Service isConnected", file=sys
.stderr
)
403 return self
.server
!= None
404 def getCurrentConnectionContext(self
):
406 print("PyMailPOP3Service getCurrentConnectionContext", file=sys
.stderr
)
407 return self
.connectioncontext
409 class PyMailServiceProvider(unohelper
.Base
, XMailServiceProvider
, XServiceInfo
):
410 def __init__( self
, ctx
):
412 print("PyMailServiceProvider init", file=sys
.stderr
)
414 def create(self
, aType
):
416 print("PyMailServiceProvider create with", aType
, file=sys
.stderr
)
418 return PyMailSMTPService(self
.ctx
);
420 return PyMailPOP3Service(self
.ctx
);
422 return PyMailIMAPService(self
.ctx
);
424 print("PyMailServiceProvider, unknown TYPE " + aType
, file=sys
.stderr
)
426 def getImplementationName(self
):
427 return g_providerImplName
429 def supportsService(self
, ServiceName
):
430 return g_ImplementationHelper
.supportsService(g_providerImplName
, ServiceName
)
432 def getSupportedServiceNames(self
):
433 return g_ImplementationHelper
.getSupportedServiceNames(g_providerImplName
)
435 class PyMailMessage(unohelper
.Base
, XMailMessage
):
436 def __init__( self
, ctx
, sTo
='', sFrom
='', Subject
='', Body
=None, aMailAttachment
=None ):
438 print("PyMailMessage init", file=sys
.stderr
)
441 self
.recipients
= [sTo
]
442 self
.ccrecipients
= []
443 self
.bccrecipients
= []
444 self
.aMailAttachments
= []
445 if aMailAttachment
!= None:
446 self
.aMailAttachments
.append(aMailAttachment
)
448 self
.SenderName
, self
.SenderAddress
= parseaddr(sFrom
)
449 self
.ReplyToAddress
= sFrom
450 self
.Subject
= Subject
453 print("post PyMailMessage init", file=sys
.stderr
)
454 def addRecipient( self
, recipient
):
456 print("PyMailMessage.addRecipient: " + recipient
, file=sys
.stderr
)
457 self
.recipients
.append(recipient
)
458 def addCcRecipient( self
, ccrecipient
):
460 print("PyMailMessage.addCcRecipient: " + ccrecipient
, file=sys
.stderr
)
461 self
.ccrecipients
.append(ccrecipient
)
462 def addBccRecipient( self
, bccrecipient
):
464 print("PyMailMessage.addBccRecipient: " + bccrecipient
, file=sys
.stderr
)
465 self
.bccrecipients
.append(bccrecipient
)
466 def getRecipients( self
):
468 print("PyMailMessage.getRecipients: " + str(self
.recipients
), file=sys
.stderr
)
469 return tuple(self
.recipients
)
470 def getCcRecipients( self
):
472 print("PyMailMessage.getCcRecipients: " + str(self
.ccrecipients
), file=sys
.stderr
)
473 return tuple(self
.ccrecipients
)
474 def getBccRecipients( self
):
476 print("PyMailMessage.getBccRecipients: " + str(self
.bccrecipients
), file=sys
.stderr
)
477 return tuple(self
.bccrecipients
)
478 def addAttachment( self
, aMailAttachment
):
480 print("PyMailMessage.addAttachment", file=sys
.stderr
)
481 self
.aMailAttachments
.append(aMailAttachment
)
482 def getAttachments( self
):
484 print("PyMailMessage.getAttachments", file=sys
.stderr
)
485 return tuple(self
.aMailAttachments
)
487 def getImplementationName(self
):
488 return g_messageImplName
490 def supportsService(self
, ServiceName
):
491 return g_ImplementationHelper
.supportsService(g_messageImplName
, ServiceName
)
493 def getSupportedServiceNames(self
):
494 return g_ImplementationHelper
.getSupportedServiceNames(g_messageImplName
)
496 g_ImplementationHelper
.addImplementation( \
497 PyMailServiceProvider
, g_providerImplName
,
498 ("com.sun.star.mail.MailServiceProvider",),)
499 g_ImplementationHelper
.addImplementation( \
500 PyMailMessage
, g_messageImplName
,
501 ("com.sun.star.mail.MailMessage",),)
503 # vim: set shiftwidth=4 softtabstop=4 expandtab: