coddingtonbear / django-mailbox

Import mail from POP3, IMAP, local email mailboxes or directly from Postfix or Exim4 into your Django application automatically.
MIT License
356 stars 165 forks source link

Best way to implement IMAP IDLE? #186

Open TravisDart opened 6 years ago

TravisDart commented 6 years ago

I have an IMAP inbox and I want to listen for incoming mail. IMAP-wise, this can be done with the IDLE command. What would be the best way to implement this in Django Mailbox?

Currently, Django Mailbox uses imaplib, which doesn't natively support IDLE. One solution monkey patches imaplib. While monkey-patching is generally undesirable, the solution looks minimally invasive. (Note that I haven't delved into the implementation details of IDLE or tested this code.)

There's also an imaplib2 module (src) which supports IDLE, and replaces imaplib (with caveats). Yet changing modules seem more invasive that the monkey patch above.

As far as Django Mailbox goes, maybe a watch() method could be added to the ImapTransport class and run with a management command?

conn = mailbox.get_connection()
conn.watch()
ad-m commented 6 years ago

@TravisDart , are you sure imaplib2 support watch? See https://github.com/imaplib2/imaplib2/search?utf8=%E2%9C%93&q=watch&type= .

I think it's best to do it based on imaplib2. This requires the introduction of a pluggable transport backend mechanism. Now lists of backend are hard-coded ( https://github.com/coddingtonbear/django-mailbox/blob/e0687380a1d6cf3aa0958c8cf5d1d532934d8d49/django_mailbox/models.py#L182-L226 ). Next to a new one back-end extend EmailTransport and can use watch.

I do not have free time to implement it, but I can assist.

TravisDart commented 6 years ago

The watch() method would an addition to Django Mailbox and would fetch messages from imaplib2 and store the messages in Django.

So, rather than change the existing ImapTransport, we should create another transport (say, StreamingImapTransport) and integrate it into Django Mailbox through a new pluggable transport system? Not quite sure what you're envisioning with the pluggable transport system.

ad-m commented 6 years ago

I think that the selected code snippet requires rewriting so that it is possible to dynamically add pluggable forms of transport (protocol) and then add StreamingImapTransport outside the django-mailbox. Maybe replace line https://github.com/coddingtonbear/django-mailbox/blob/e0687380a1d6cf3aa0958c8cf5d1d532934d8d49/django_mailbox/models.py#L226 to something like

transport_registry.get_for_type(self.type).from_uri(self.uri)

I also think that there should be a new transport instead of modifying the current one.

TravisDart commented 6 years ago

It sound like it'd be best to make each 3rd-party transport a Django app. The transport could add itself to the transport registry in the app.py.

Honestly, it seems we're drifting off topic. I was wanting to implement IMAP IDLE, and I'm now implementing a pluggable transport system. I guess this is okay if it doesn't take us too far out of our way, but I was kind of thinking it'd just be a matter of hard-coding another transport like we already have.

ad-m commented 6 years ago

@TravisDart , I added some POC of pluggable transport registry: https://github.com/coddingtonbear/django-mailbox/pull/188

I'd rather not add additional dependency to this library. Therefore, transports that use atypical libraries must be pluggable so that you can simply add custom transports with non-standard dependencies.