mirror of
https://github.com/coddingtonbear/django-mailbox.git
synced 2026-07-09 22:38:19 +02:00
Office365 API mailbox support (#251)
* Update models.py, __init__.py, and office365.py * Update setup.py * Office365Transport properties * Update .gitignore * wrong folder stage * Update models.py * Update office365.py and models.py * office365 implementation * Update office365.py * clear code * fix import * Update readme.rst * archive and delete * fix and documentation * removed build folder * missing archive Co-authored-by: Pietro Mingo <p.mingo@intac.it> Co-authored-by: Serafim Bordei <s.bordei@intac.it>
This commit is contained in:
parent
40263b6670
commit
cefbcdebd2
8 changed files with 129 additions and 3 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -13,3 +13,4 @@ dummy_project/*
|
||||||
.tox/
|
.tox/
|
||||||
messages
|
messages
|
||||||
*.sqlite3
|
*.sqlite3
|
||||||
|
.idea/
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ from django_mailbox import utils
|
||||||
from django_mailbox.signals import message_received
|
from django_mailbox.signals import message_received
|
||||||
from django_mailbox.transports import Pop3Transport, ImapTransport, \
|
from django_mailbox.transports import Pop3Transport, ImapTransport, \
|
||||||
MaildirTransport, MboxTransport, BabylTransport, MHTransport, \
|
MaildirTransport, MboxTransport, BabylTransport, MHTransport, \
|
||||||
MMDFTransport, GmailImapTransport
|
MMDFTransport, GmailImapTransport, Office365Transport
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -189,6 +189,30 @@ class Mailbox(models.Model):
|
||||||
return None
|
return None
|
||||||
return folder[0]
|
return folder[0]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def client_id(self):
|
||||||
|
"""Returns (if specified) the client id for Office365."""
|
||||||
|
client_id = self._query_string.get('client_id', None)
|
||||||
|
if not client_id:
|
||||||
|
return None
|
||||||
|
return client_id[0]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def client_secret(self):
|
||||||
|
"""Returns (if specified) the client secret for Office365."""
|
||||||
|
client_secret = self._query_string.get('client_secret', None)
|
||||||
|
if not client_secret:
|
||||||
|
return None
|
||||||
|
return client_secret[0]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tenant_id(self):
|
||||||
|
"""Returns (if specified) the tenant id for Office365."""
|
||||||
|
tenant_id = self._query_string.get('tenant_id', None)
|
||||||
|
if not tenant_id:
|
||||||
|
return None
|
||||||
|
return tenant_id[0]
|
||||||
|
|
||||||
def get_connection(self):
|
def get_connection(self):
|
||||||
"""Returns the transport instance for this mailbox.
|
"""Returns the transport instance for this mailbox.
|
||||||
|
|
||||||
|
|
@ -223,6 +247,14 @@ class Mailbox(models.Model):
|
||||||
ssl=self.use_ssl
|
ssl=self.use_ssl
|
||||||
)
|
)
|
||||||
conn.connect(self.username, self.password)
|
conn.connect(self.username, self.password)
|
||||||
|
elif self.type == 'office365':
|
||||||
|
conn = Office365Transport(
|
||||||
|
self.location,
|
||||||
|
self.username,
|
||||||
|
folder=self.folder,
|
||||||
|
archive=self.archive
|
||||||
|
)
|
||||||
|
conn.connect(self.client_id, self.client_secret, self.tenant_id)
|
||||||
elif self.type == 'maildir':
|
elif self.type == 'maildir':
|
||||||
conn = MaildirTransport(self.location)
|
conn = MaildirTransport(self.location)
|
||||||
elif self.type == 'mbox':
|
elif self.type == 'mbox':
|
||||||
|
|
|
||||||
|
|
@ -8,3 +8,4 @@ from django_mailbox.transports.babyl import BabylTransport
|
||||||
from django_mailbox.transports.mh import MHTransport
|
from django_mailbox.transports.mh import MHTransport
|
||||||
from django_mailbox.transports.mmdf import MMDFTransport
|
from django_mailbox.transports.mmdf import MMDFTransport
|
||||||
from django_mailbox.transports.gmail import GmailImapTransport
|
from django_mailbox.transports.gmail import GmailImapTransport
|
||||||
|
from django_mailbox.transports.office365 import Office365Transport
|
||||||
|
|
|
||||||
|
|
@ -9,3 +9,4 @@ class EmailTransport:
|
||||||
message = email.message_from_bytes(contents)
|
message = email.message_from_bytes(contents)
|
||||||
|
|
||||||
return message
|
return message
|
||||||
|
|
||||||
|
|
|
||||||
66
django_mailbox/transports/office365.py
Normal file
66
django_mailbox/transports/office365.py
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
from .base import EmailTransport, MessageParseError
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class Office365Transport(EmailTransport):
|
||||||
|
def __init__(
|
||||||
|
self, hostname, username, archive='', folder=None
|
||||||
|
):
|
||||||
|
self.integration_testing_subject = getattr(
|
||||||
|
settings,
|
||||||
|
'DJANGO_MAILBOX_INTEGRATION_TESTING_SUBJECT',
|
||||||
|
None
|
||||||
|
)
|
||||||
|
self.hostname = hostname
|
||||||
|
self.username = username
|
||||||
|
self.archive = archive
|
||||||
|
self.folder = folder
|
||||||
|
|
||||||
|
def connect(self, client_id, client_secret, tenant_id):
|
||||||
|
try:
|
||||||
|
import O365
|
||||||
|
except ImportError:
|
||||||
|
raise ValueError(
|
||||||
|
"Install o365 to use oauth2 auth for office365"
|
||||||
|
)
|
||||||
|
|
||||||
|
credentials = (client_id, client_secret)
|
||||||
|
|
||||||
|
self.account = O365.Account(credentials, auth_flow_type='credentials', tenant_id=tenant_id)
|
||||||
|
self.account.authenticate()
|
||||||
|
|
||||||
|
self.mailbox = self.account.mailbox(resource=self.username)
|
||||||
|
self.mailbox_folder = self.mailbox.inbox_folder()
|
||||||
|
if self.folder:
|
||||||
|
self.mailbox_folder = self.mailbox.get_folder(folder_name=self.folder)
|
||||||
|
|
||||||
|
def get_message(self, condition=None):
|
||||||
|
archive_folder = None
|
||||||
|
if self.archive:
|
||||||
|
archive_folder = self.mailbox.get_folder(folder_name=self.archive)
|
||||||
|
if not archive_folder:
|
||||||
|
archive_folder = self.mailbox.create_child_folder(self.archive)
|
||||||
|
|
||||||
|
for o365message in self.mailbox_folder.get_messages(order_by='receivedDateTime'):
|
||||||
|
try:
|
||||||
|
mime_content = o365message.get_mime_content()
|
||||||
|
message = self.get_email_from_bytes(mime_content)
|
||||||
|
|
||||||
|
if condition and not condition(message):
|
||||||
|
continue
|
||||||
|
|
||||||
|
yield message
|
||||||
|
except MessageParseError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if self.archive and archive_folder:
|
||||||
|
o365message.copy(archive_folder)
|
||||||
|
|
||||||
|
o365message.delete()
|
||||||
|
return
|
||||||
|
|
||||||
|
|
@ -13,6 +13,7 @@ POP3 and IMAP as well as local file-based mailboxes.
|
||||||
POP3 ``pop3://`` Can also specify SSL with ``pop3+ssl://``
|
POP3 ``pop3://`` Can also specify SSL with ``pop3+ssl://``
|
||||||
IMAP ``imap://`` Can also specify SSL with ``imap+ssl://`` or STARTTLS with ``imap+tls``; additional configuration is also possible: see :ref:`pop3-and-imap-mailboxes` for details.
|
IMAP ``imap://`` Can also specify SSL with ``imap+ssl://`` or STARTTLS with ``imap+tls``; additional configuration is also possible: see :ref:`pop3-and-imap-mailboxes` for details.
|
||||||
Gmail IMAP ``gmail+ssl://`` Uses OAuth authentication for Gmail's IMAP transport. See :ref:`gmail-oauth` for details.
|
Gmail IMAP ``gmail+ssl://`` Uses OAuth authentication for Gmail's IMAP transport. See :ref:`gmail-oauth` for details.
|
||||||
|
Office365 API``office365://`` Uses OAuth authentication for Office365 API transport. See :ref:`office365-oauth` for details.
|
||||||
Maildir ``maildir://``
|
Maildir ``maildir://``
|
||||||
Mbox ``mbox://``
|
Mbox ``mbox://``
|
||||||
Babyl ``babyl://``
|
Babyl ``babyl://``
|
||||||
|
|
@ -115,6 +116,25 @@ Build your URI accordingly::
|
||||||
gmail+ssl://youremailaddress%40gmail.com:oauth2@imap.gmail.com?archive=Archived
|
gmail+ssl://youremailaddress%40gmail.com:oauth2@imap.gmail.com?archive=Archived
|
||||||
|
|
||||||
|
|
||||||
|
.. _office365-oauth:
|
||||||
|
Office 365 API
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
Office 365 allows through the API to read a mailbox with Oauth.
|
||||||
|
The O365_ library is used.
|
||||||
|
|
||||||
|
.. _O365: https://github.com/O365/python-o365
|
||||||
|
.. _configuration: https://github.com/O365/python-o365#authentication
|
||||||
|
|
||||||
|
For the configuration_ you need to register an application and get a client_id, client_secret and tenant_id.
|
||||||
|
|
||||||
|
This implementation uses the client credentials grant flow and the password you specify will be ignored.
|
||||||
|
|
||||||
|
Build your URI accordingly::
|
||||||
|
|
||||||
|
office365://youremailaddress%40yourdomain.com:oauth2@outlook.office365.com?client_id=client_id&client_secret=client_secret&tenant_id=tenant_id&archive=Archived
|
||||||
|
|
||||||
|
|
||||||
Local File-based Mailboxes
|
Local File-based Mailboxes
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
:target: https://pypi.python.org/pypi/django-mailbox
|
:target: https://pypi.python.org/pypi/django-mailbox
|
||||||
|
|
||||||
|
|
||||||
Easily ingest messages from POP3, IMAP, or local mailboxes into your Django application.
|
Easily ingest messages from POP3, IMAP, Office365 API or local mailboxes into your Django application.
|
||||||
|
|
||||||
This app allows you to either ingest e-mail content from common e-mail services (as long as the service provides POP3 or IMAP support),
|
This app allows you to either ingest e-mail content from common e-mail services (as long as the service provides POP3 or IMAP support),
|
||||||
or directly receive e-mail messages from ``stdin`` (for locally processing messages from Postfix or Exim4).
|
or directly receive e-mail messages from ``stdin`` (for locally processing messages from Postfix or Exim4).
|
||||||
|
|
|
||||||
7
setup.py
7
setup.py
|
|
@ -13,6 +13,10 @@ gmail_oauth2_require = [
|
||||||
'python-social-auth',
|
'python-social-auth',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
office365_oauth2_require = [
|
||||||
|
'O365',
|
||||||
|
]
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='django-mailbox',
|
name='django-mailbox',
|
||||||
version=version_string,
|
version=version_string,
|
||||||
|
|
@ -25,7 +29,8 @@ setup(
|
||||||
author='Adam Coddington',
|
author='Adam Coddington',
|
||||||
author_email='me@adamcoddington.net',
|
author_email='me@adamcoddington.net',
|
||||||
extras_require={
|
extras_require={
|
||||||
'gmail-oauth2': gmail_oauth2_require
|
'gmail-oauth2': gmail_oauth2_require,
|
||||||
|
'office365-oauth2': office365_oauth2_require
|
||||||
},
|
},
|
||||||
python_requires=">=3",
|
python_requires=">=3",
|
||||||
classifiers=[
|
classifiers=[
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue