mail (IMAP) integration basically working
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@3537 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
90b67d1265
commit
a78ec01d5c
6 changed files with 107 additions and 36 deletions
|
@ -38,7 +38,7 @@ of the 'extcollection' type. We use an adapter for providing the attributes
|
|||
and methods of the external collect object.
|
||||
|
||||
>>> from loops.concept import Concept
|
||||
>>> from loops.setup import addObject
|
||||
>>> from loops.setup import addObject, addAndConfigureObject
|
||||
>>> from loops.integrator.collection import ExternalCollectionAdapter
|
||||
>>> tExternalCollection = concepts['extcollection']
|
||||
>>> coll01 = addObject(concepts, Concept, 'coll01',
|
||||
|
@ -141,10 +141,10 @@ Mail Collections
|
|||
|
||||
>>> tType = concepts['type']
|
||||
>>> from loops.integrator.mail.interfaces import IMailCollection, IMailResource
|
||||
>>> tMailCollection = addObject(concepts, Concept, 'mailcollection',
|
||||
>>> tMailCollection = addAndConfigureObject(concepts, Concept, 'mailcollection',
|
||||
... title=u'Mail Collection', conceptType=tType,
|
||||
... typeInterface=IMailCollection)
|
||||
>>> tMailResource = addObject(concepts, Concept, 'email',
|
||||
>>> tMailResource = addAndConfigureObject(concepts, Concept, 'email',
|
||||
... title=u'Mail Resource', conceptType=tType,
|
||||
... typeInterface=IMailResource)
|
||||
|
||||
|
@ -157,17 +157,28 @@ Mail Collections
|
|||
An external collection carries a set of attributes that control the access
|
||||
to the external system:
|
||||
|
||||
>>> (aMailColl.providerName, aMailColl.baseAddress,
|
||||
... aMailColl.address, aMailColl.pattern)
|
||||
(u'imap', None, None, None)
|
||||
>>> aMailColl.userName = u'jim'
|
||||
>>> (aMailColl.providerName, aMailColl.baseAddress, aMailColl.address,
|
||||
... aMailColl.pattern, aMailColl.userName)
|
||||
(u'imap', None, None, None, u'jim')
|
||||
|
||||
>>> from loops.integrator.mail import testing
|
||||
|
||||
>>> from loops.integrator.mail.imap import IMAPCollectionProvider
|
||||
>>> component.provideUtility(IMAPCollectionProvider(), name='imap')
|
||||
>>> from loops.integrator.mail.resource import MailResource
|
||||
>>> component.provideAdapter(MailResource, provides=IMailResource)
|
||||
|
||||
>>> aMailColl.update()
|
||||
*** 1 ...
|
||||
|
||||
>>> aMail = adapted(mailColl.getResources()[0])
|
||||
|
||||
>>> aMail.date, aMail.sender, aMail.receiver, aMail.title
|
||||
(datetime.datetime(...), 'ceo@cy55.de', 'ceo@example.org', 'Blogging from Munich')
|
||||
>>> aMail.data
|
||||
'<p><b>Blogging from ...</b><br />\n'
|
||||
>>> aMail.externalAddress
|
||||
u'imap://jim@merz12/20081208171745.e4ce2xm96cco80cg@cy55.de'
|
||||
|
||||
|
||||
Uploading Resources with HTTP PUT Requests
|
||||
|
|
|
@ -84,7 +84,7 @@ class ExternalCollectionAdapter(AdapterBase):
|
|||
# may be it would be better to return a file's hash
|
||||
# for checking for changes...
|
||||
oldFound.append(addr)
|
||||
if mdate > self.lastUpdated:
|
||||
if mdate and mdate > self.lastUpdated:
|
||||
# force reindexing
|
||||
notify(ObjectModifiedEvent(old[addr]))
|
||||
else:
|
||||
|
|
|
@ -20,4 +20,15 @@
|
|||
factory="loops.integrator.mail.imap.IMAPCollectionProvider"
|
||||
name="imap" />
|
||||
|
||||
<zope:adapter factory="loops.integrator.mail.resource.MailResource"
|
||||
provides="loops.integrator.mail.interfaces.IMailResource"
|
||||
trusted="True" />
|
||||
|
||||
<zope:class class="loops.integrator.mail.resource.MailResource">
|
||||
<require permission="zope.View"
|
||||
interface="loops.integrator.mail.interfaces.IMailResource" />
|
||||
<require permission="zope.ManageContent"
|
||||
set_schema="loops.integrator.mail.interfaces.IMailResource" />
|
||||
</zope:class>
|
||||
|
||||
</configure>
|
||||
|
|
|
@ -24,14 +24,18 @@ $Id$
|
|||
"""
|
||||
|
||||
from datetime import datetime
|
||||
import email
|
||||
from logging import getLogger
|
||||
import os
|
||||
import time
|
||||
|
||||
from zope.app.container.interfaces import INameChooser
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
from zope import component
|
||||
from zope.component import adapts
|
||||
from zope.event import notify
|
||||
from zope.lifecycleevent import ObjectModifiedEvent
|
||||
from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
|
||||
from zope.event import notify
|
||||
from zope.interface import implements
|
||||
from zope.traversing.api import getName, getParent
|
||||
|
||||
|
@ -51,6 +55,10 @@ class IMAPCollectionProvider(object):
|
|||
|
||||
def collect(self, client):
|
||||
client._collectedObjects = {}
|
||||
hostName = client.baseAddress
|
||||
if hostName in ('', None, 'localhost'):
|
||||
hostName = os.uname()[1]
|
||||
baseId = 'imap://%s@%s' % (client.userName, hostName)
|
||||
imap = IMAP4(client.baseAddress)
|
||||
imap.login(client.userName, client.password)
|
||||
mailbox = 'INBOX'
|
||||
|
@ -61,11 +69,13 @@ class IMAPCollectionProvider(object):
|
|||
type, data = imap.search(None, 'ALL')
|
||||
for num in data[0].split():
|
||||
type, data = imap.fetch(num, '(RFC822)')
|
||||
externalAddress = num
|
||||
obj = data
|
||||
mtime = datetime.today()
|
||||
client._collectedObjects[externalAddress] = obj
|
||||
yield externalAddress, mtime
|
||||
raw_msg = data[0][1]
|
||||
msg = email.message_from_string(raw_msg)
|
||||
msgId = msg['Message-ID'].replace('<', '').replace('>', '')
|
||||
externalAddress = '/'.join((baseId, msgId))
|
||||
#mtime = datetime.today()
|
||||
client._collectedObjects[externalAddress] = msg
|
||||
yield externalAddress, None
|
||||
|
||||
def createExtFileObjects(self, client, addresses, extFileTypes=None):
|
||||
loopsRoot = client.context.getLoopsRoot()
|
||||
|
@ -73,16 +83,43 @@ class IMAPCollectionProvider(object):
|
|||
contentType = 'text/plain'
|
||||
resourceType = loopsRoot.getConceptManager()['email']
|
||||
for addr in addresses:
|
||||
print '***', addr, client._collectedObjects[addr]
|
||||
return []
|
||||
|
||||
def _dummy(self):
|
||||
name = self.generateName(container, addr)
|
||||
title = self.generateTitle(addr)
|
||||
obj = addAndConfigureObject(
|
||||
container, Resource, name,
|
||||
title=title,
|
||||
resourceType=extFileType,
|
||||
contentType=contentType,
|
||||
)
|
||||
msg = client._collectedObjects[addr]
|
||||
title = msg['Subject']
|
||||
sender = msg['From']
|
||||
receiver = msg['To']
|
||||
raw_date = msg['Date'].rsplit(' ', 1)[0]
|
||||
fmt = '%a, %d %b %Y %H:%M:%S'
|
||||
date = datetime(*(time.strptime(raw_date, fmt)[0:6]))
|
||||
parts = self.getPayload(msg, {})
|
||||
if 'html' in parts:
|
||||
text = parts['html']
|
||||
ct = 'text/html'
|
||||
else:
|
||||
text = parts.get('plain') or u'No message found.'
|
||||
ct = 'text/plain'
|
||||
obj = Resource(title)
|
||||
name = INameChooser(container).chooseName(None, obj)
|
||||
container[name] = obj
|
||||
obj.resourceType = resourceType
|
||||
adObj = adapted(obj)
|
||||
adObj.externalAddress = addr
|
||||
adObj.contentType = ct
|
||||
adObj.sender = sender
|
||||
adObj.receiver = receiver
|
||||
adObj.date = date
|
||||
adObj.data = text
|
||||
notify(ObjectCreatedEvent(obj))
|
||||
notify(ObjectModifiedEvent(obj))
|
||||
yield obj
|
||||
|
||||
def getPayload(self, msg, parts):
|
||||
if msg.is_multipart():
|
||||
for part in msg.get_payload():
|
||||
self.getPayload(part, parts)
|
||||
else:
|
||||
ct = msg['Content-Type']
|
||||
if ct and ct.startswith('text/html'):
|
||||
parts['html'] = msg.get_payload()
|
||||
if ct and ct.startswith('text/plain'):
|
||||
parts['plain'] = msg.get_payload()
|
||||
return parts
|
||||
|
|
|
@ -41,14 +41,13 @@ class IMailCollection(IExternalCollection):
|
|||
providerName = schema.TextLine(
|
||||
title=_(u'Provider name'),
|
||||
description=_(u'The name of a utility that provides the '
|
||||
u'external objects; default is an IMAP '
|
||||
u'collection provider.'),
|
||||
u'external objects; default is an IMAP collection provider.'),
|
||||
default=u'imap',
|
||||
required=False)
|
||||
baseAddress = schema.TextLine(
|
||||
title=_(u'Host name'),
|
||||
description=_(u'The host name part for accessing the '
|
||||
u'external mail system, i.e. the mail server.'),
|
||||
u'external mail system, i.e. the mail server.'),
|
||||
required=True)
|
||||
userName = schema.TextLine(
|
||||
title=_(u'User name'),
|
||||
|
@ -67,9 +66,22 @@ class IMailResource(ITextDocument):
|
|||
"""
|
||||
|
||||
externalAddress = schema.BytesLine(
|
||||
title=_(u'External Address'),
|
||||
description=_(u'The full address of the email in the external '
|
||||
u'email system.'),
|
||||
default='',
|
||||
missing_value='',
|
||||
required=False)
|
||||
title=_(u'External Address'),
|
||||
description=_(u'The full address of the email in the external '
|
||||
u'email system.'),
|
||||
default='',
|
||||
missing_value='',
|
||||
required=False)
|
||||
sender = schema.TextLine(
|
||||
title=_(u'Sender'),
|
||||
description=_(u'The email address of sender of the email.'),
|
||||
required=False)
|
||||
receiver = schema.TextLine(
|
||||
title=_(u'Receiver'),
|
||||
description=_(u'One or more email addresses of the receiver(s) of '
|
||||
u'the email message.'),
|
||||
required=False)
|
||||
date = schema.Date(
|
||||
title=_(u'Date'),
|
||||
description=_(u'The date/time the email message was sent.'),
|
||||
required=False,)
|
||||
|
|
|
@ -22,7 +22,7 @@ Fake access to system libraries for testing.
|
|||
$Id$
|
||||
"""
|
||||
|
||||
data = [('1 (RFC822 {7785}', 'Return-Path: <ceo-bounces@mailman.cy55.de>\r\nMessage-ID: <20081208171745.e4ce2xm96cco80cg@cy55.de>\r\nDate: Mon, 8 Dec 2008 17:17:45 +0100\r\nFrom: ceo@cy55.de\r\nTo: ceo@example.org\r\n\r\nThis message is in MIME format.\r\n\r\n--===============0371775080==\r\nContent-Type: multipart/alternative;\r\n\tboundary="=_gtkn1bgzg6g"\r\nContent-Transfer-Encoding: 7bit\r\n\r\nThis message is in MIME format.\r\n\r\n--=_gtkn1bgzg6g\r\nContent-Type: text/plain;\r\n\tcharset=ISO-8859-1;\r\n\tDelSp="Yes";\r\n\tformat="flowed"\r\nContent-Description: Plaintext Version of Message\r\nContent-Disposition: inline\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\n\r\n\r\n BLOGGING FROM ...\r\n.\r\n\r\n\r\n--=_gtkn1bgzg6g\r\nContent-Type: text/html;\r\n\tcharset=ISO-8859-1\r\nContent-Description: HTML Version of Message\r\nContent-Disposition: inline\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\n<p><b>Blogging from ...</b><br />\r\n\r\n'), ')']
|
||||
data = [('1 (RFC822 {7785}', 'Return-Path: <ceo-bounces@mailman.cy55.de>\r\nMessage-ID: <20081208171745.e4ce2xm96cco80cg@cy55.de>\r\nDate: Mon, 8 Dec 2008 17:17:45 +0100\r\nFrom: ceo@cy55.de\r\nTo: ceo@example.org\r\nMIME-Version: 1.0\r\nSubject: Blogging from Munich\r\nContent-Type: multipart/mixed;\r\n\tboundary="===============0371775080=="\r\n\r\nThis message is in MIME format.\r\n\r\n--===============0371775080==\r\nContent-Type: multipart/alternative;\r\n\tboundary="=_gtkn1bgzg6g"\r\nContent-Transfer-Encoding: 7bit\r\n\r\nThis message is in MIME format.\r\n\r\n--=_gtkn1bgzg6g\r\nContent-Type: text/plain;\r\n\tcharset=ISO-8859-1;\r\n\tDelSp="Yes";\r\n\tformat="flowed"\r\nContent-Description: Plaintext Version of Message\r\nContent-Disposition: inline\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\n\r\n\r\n BLOGGING FROM ...\r\n.\r\n\r\n\r\n--=_gtkn1bgzg6g\r\nContent-Type: text/html;\r\n\tcharset=ISO-8859-1\r\nContent-Description: HTML Version of Message\r\nContent-Disposition: inline\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\n<p><b>Blogging from ...</b><br />\r\n\r\n'), ')']
|
||||
|
||||
|
||||
class IMAP4(object):
|
||||
|
|
Loading…
Add table
Reference in a new issue