Documentation for pulsar 0.9.2. For development docs, go here.
'''The example is a :ref:`WSGI application <apps-wsgi>`
with a :ref:`websocket middleware <apps-ws>` which connects to an
IMAP4 server to retrieve and send emails.
The connection with the IMAP4 server is obtained using the IMAP4 API in
twisted 12.3 or later. The example uses
:ref:`pulsar-twisted integration <tutorials-twisted>` module.
To run the server you need to create a :mod:`config.py` file in the
the :mod:`examples.webmail` directory containing::
# the adress of your mail server
mail_incoming ='ssl:host=imap.gmail.com:port=993'
# mail_username & mail_password
mail_username=
mail_password=
And type::
python manage.py
Open a web browser at http://localhost:8060 and you should see the web app.
For information on twisted IMAP4 client library check this example:
http://twistedmatrix.com/documents/current/mail/examples/imap4client.py
Other python examples of webmail:
* https://github.com/khamidou/kite
Implementation
==================
.. autoclass:: WsMail
:members:
:member-order: bysource
'''
import os
import sys
from pulsar.apps import ws, wsgi
from pulsar.utils.log import process_global
from pulsar.utils.system import json
try:
twisted = True
from pulsar.apps.tx import tx
from twisted.internet import protocol, endpoints, reactor
from twisted.internet.defer import returnValue
from twisted.mail import imap4
except ImportError: # pragma nocover
tx = lambda x: x
twisted = False # This is for when we build docs
ASSET_DIR = os.path.join(os.path.dirname(__file__), 'assets')
@tx
def mail_client(cfg, timeout=10):
'''Create a new mail client using twisted IMAP4 library.'''
assert twisted, 'Twisted is not available'
key = (cfg.mail_incoming, cfg.mail_username, cfg.mail_password)
client = process_global(key)
if not client:
endpoint = endpoints.clientFromString(reactor, cfg.mail_incoming)
endpoint._timeout = timeout
factory = protocol.Factory()
factory.protocol = imap4.IMAP4Client
client = yield endpoint.connect(factory)
yield client.login(cfg.mail_username, cfg.mail_password)
yield client.select('INBOX')
process_global(key, client, True)
returnValue(client)
# info = yield client.fetchEnvelope(imap4.MessageSet(1))
# print 'First message subject:', info[1]['ENVELOPE'][1]
[docs]class WsMail(ws.WS):
'''A :class:`.WS` handler for fetching and sending mail via the
twisted IMAP4 library
'''
[docs] def on_open(self, websocket):
'''When the websocket starts, it create a new mail client.'''
request = websocket.handshake
client = yield mail_client(request.cfg)
# add the mail client to the environ cache
request.cache.mailclient = client
# retrieve the list of mailboxes and them to the client
yield self._send_mailboxes(websocket)
def on_message(self, websocket, msg):
request = websocket.request
client = request.cache.mailclient
if msg and client:
msg = json.loads(msg)
if 'mailbox' in msg:
mailbox = yield client.examine(msg['mailbox'])
self.write(request, json.dumps({'mailbox': mailbox}))
@tx
def _send_mailboxes(self, websocket):
request = websocket.handshake
result = yield request.cache.mailclient.list("", "*")
result = sorted([e[2] for e in result])
websocket.write(json.dumps({'list': result}))
class WebMail(wsgi.LazyWsgi):
def setup(self, environ):
return wsgi.WsgiHandler([ws.WebSocket('/message', WsMail()),
wsgi.MediaRouter('/media', ASSET_DIR),
wsgi.Router('/', get=self.home)])
def home(self, request):
data = open(os.path.join(ASSET_DIR, 'mail.html')).read()
response = request.response
request.response.content = data % request.environ
request.response.content_type = 'text/html'
return response
def server(name='webmail', callable=None, **kwargs):
return wsgi.WSGIServer(name=name, callable=WebMail(), **kwargs)
if __name__ == '__main__': # pragma nocover
server().start()