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/
|
||||
messages
|
||||
*.sqlite3
|
||||
.idea/
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ from django_mailbox import utils
|
|||
from django_mailbox.signals import message_received
|
||||
from django_mailbox.transports import Pop3Transport, ImapTransport, \
|
||||
MaildirTransport, MboxTransport, BabylTransport, MHTransport, \
|
||||
MMDFTransport, GmailImapTransport
|
||||
MMDFTransport, GmailImapTransport, Office365Transport
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -189,6 +189,30 @@ class Mailbox(models.Model):
|
|||
return None
|
||||
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):
|
||||
"""Returns the transport instance for this mailbox.
|
||||
|
||||
|
|
@ -223,6 +247,14 @@ class Mailbox(models.Model):
|
|||
ssl=self.use_ssl
|
||||
)
|
||||
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':
|
||||
conn = MaildirTransport(self.location)
|
||||
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.mmdf import MMDFTransport
|
||||
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)
|
||||
|
||||
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://``
|
||||
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.
|
||||
Office365 API``office365://`` Uses OAuth authentication for Office365 API transport. See :ref:`office365-oauth` for details.
|
||||
Maildir ``maildir://``
|
||||
Mbox ``mbox://``
|
||||
Babyl ``babyl://``
|
||||
|
|
@ -115,6 +116,25 @@ Build your URI accordingly::
|
|||
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
|
||||
--------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
: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),
|
||||
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',
|
||||
]
|
||||
|
||||
office365_oauth2_require = [
|
||||
'O365',
|
||||
]
|
||||
|
||||
setup(
|
||||
name='django-mailbox',
|
||||
version=version_string,
|
||||
|
|
@ -25,7 +29,8 @@ setup(
|
|||
author='Adam Coddington',
|
||||
author_email='me@adamcoddington.net',
|
||||
extras_require={
|
||||
'gmail-oauth2': gmail_oauth2_require
|
||||
'gmail-oauth2': gmail_oauth2_require,
|
||||
'office365-oauth2': office365_oauth2_require
|
||||
},
|
||||
python_requires=">=3",
|
||||
classifiers=[
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue