forked from extern/django-helpdesk
Add IMAP OAUTH Mail Box Type
This commit is contained in:
parent
26628db7e0
commit
d57f11f40a
@ -21,6 +21,11 @@ import email
|
||||
from email.message import Message
|
||||
from email.utils import getaddresses
|
||||
from email_reply_parser import EmailReplyParser
|
||||
|
||||
# Add OAUTH Libraries
|
||||
from oauthlib.oauth2 import BackendApplicationClient
|
||||
from requests_oauthlib import OAuth2Session
|
||||
|
||||
from helpdesk import settings
|
||||
from helpdesk.exceptions import DeleteIgnoredTicketException, IgnoreTicketException
|
||||
from helpdesk.lib import process_attachments, safe_template_context
|
||||
@ -225,6 +230,101 @@ def imap_sync(q, logger, server):
|
||||
server.logout()
|
||||
|
||||
|
||||
def imap_oauth_sync(q, logger, server):
|
||||
"""
|
||||
IMAP eMail server with OAUTH authentication.
|
||||
Only tested against O365 implementation
|
||||
|
||||
Uses OAUTH Dict in Settings.
|
||||
|
||||
"""
|
||||
|
||||
try:
|
||||
logger.debug("Start Mailbox polling via IMAP OAUTH")
|
||||
|
||||
client = BackendApplicationClient(
|
||||
client_id=django_settings.HELPDESK_OAUTH["client_id"],
|
||||
scope=django_settings.HELPDESK_OAUTH["scope"],
|
||||
)
|
||||
|
||||
oauth = OAuth2Session(client=client)
|
||||
token = oauth.fetch_token(
|
||||
token_url=django_settings.HELPDESK_OAUTH["token_url"],
|
||||
client_id=django_settings.HELPDESK_OAUTH["client_id"],
|
||||
client_secret=django_settings.HELPDESK_OAUTH["secret"],
|
||||
include_client_id=True,
|
||||
)
|
||||
|
||||
# TODO: Somehow link this to the debug level set within Django settings logging
|
||||
server.debug = 4
|
||||
|
||||
# TODO: Perhaps store the authentication string template externally? Settings? Queue Table?
|
||||
server.authenticate(
|
||||
"XOAUTH2",
|
||||
lambda x: f"user={q.email_box_user}\x01auth=Bearer {token['access_token']}\x01\x01".encode(),
|
||||
)
|
||||
|
||||
# Select the Inbound Mailbox folder
|
||||
server.select(q.email_box_imap_folder)
|
||||
|
||||
except imaplib.IMAP4.abort:
|
||||
logger.error("IMAP authentication failed.")
|
||||
server.logout()
|
||||
sys.exit()
|
||||
|
||||
except ssl.SSLError:
|
||||
logger.error(
|
||||
"IMAP login failed due to SSL error. This is often due to a timeout. "
|
||||
"Please check your connection and try again."
|
||||
)
|
||||
server.logout()
|
||||
sys.exit()
|
||||
|
||||
try:
|
||||
data = server.search(None, 'NOT', 'DELETED')[1]
|
||||
if data:
|
||||
msgnums = data[0].split()
|
||||
logger.info(f"Found {len(msgnums)} message(s) on IMAP server" )
|
||||
for num in msgnums:
|
||||
logger.info(f"Processing message {num}")
|
||||
data = server.fetch(num, '(RFC822)')[1]
|
||||
full_message = encoding.force_str(data[0][1], errors='replace')
|
||||
|
||||
try:
|
||||
ticket = object_from_message(message=full_message, queue=q, logger=logger)
|
||||
|
||||
except IgnoreTicketException as itex:
|
||||
logger.warn(f"Message {num} was ignored. {itex}")
|
||||
|
||||
except DeleteIgnoredTicketException:
|
||||
server.store(num, '+FLAGS', '\\Deleted')
|
||||
logger.warn("Message %s was ignored and deleted from IMAP server" % num)
|
||||
|
||||
except TypeError as te:
|
||||
# Log the error with stacktrace to help identify what went wrong
|
||||
logger.error(f"Unexpected error processing message: {te}", exc_info=True)
|
||||
|
||||
else:
|
||||
if ticket:
|
||||
server.store(num, '+FLAGS', '\\Deleted')
|
||||
logger.info(
|
||||
"Successfully processed message %s, deleted from IMAP server" % num)
|
||||
else:
|
||||
logger.warn(
|
||||
"Message %s was not successfully processed, and will be left on IMAP server" % num)
|
||||
|
||||
except imaplib.IMAP4.error:
|
||||
logger.error(
|
||||
"IMAP retrieve failed. Is the folder '%s' spelled correctly, and does it exist on the server?",
|
||||
q.email_box_imap_folder
|
||||
)
|
||||
|
||||
# Purged Flagged Messages & Logout
|
||||
server.expunge()
|
||||
server.close()
|
||||
server.logout()
|
||||
|
||||
|
||||
def process_queue(q, logger):
|
||||
logger.info("***** %s: Begin processing mail for django-helpdesk" % ctime())
|
||||
|
||||
@ -272,7 +372,18 @@ def process_queue(q, logger):
|
||||
'init': imaplib.IMAP4,
|
||||
},
|
||||
'sync': imap_sync
|
||||
}
|
||||
},
|
||||
'oauth': {
|
||||
'ssl': {
|
||||
'port': 993,
|
||||
'init': imaplib.IMAP4_SSL,
|
||||
},
|
||||
'insecure': {
|
||||
'port': 143,
|
||||
'init': imaplib.IMAP4,
|
||||
},
|
||||
'sync': imap_oauth_sync
|
||||
},
|
||||
}
|
||||
if email_box_type in mail_defaults:
|
||||
encryption = 'insecure'
|
||||
|
18
helpdesk/migrations/0037_alter_queue_email_box_type.py
Normal file
18
helpdesk/migrations/0037_alter_queue_email_box_type.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2.16 on 2023-03-25 15:45
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('helpdesk', '0036_add_attachment_validator'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='queue',
|
||||
name='email_box_type',
|
||||
field=models.CharField(blank=True, choices=[('pop3', 'POP 3'), ('imap', 'IMAP'), ('oauth', 'IMAP OAUTH'), ('local', 'Local Directory')], help_text='E-Mail server type for creating tickets automatically from a mailbox - both POP3 and IMAP are supported, as well as reading from a local directory.', max_length=5, null=True, verbose_name='E-Mail Box Type'),
|
||||
),
|
||||
]
|
@ -175,7 +175,9 @@ class Queue(models.Model):
|
||||
email_box_type = models.CharField(
|
||||
_('E-Mail Box Type'),
|
||||
max_length=5,
|
||||
choices=(('pop3', _('POP 3')), ('imap', _('IMAP')),
|
||||
choices=(('pop3', _('POP 3')),
|
||||
('imap', _('IMAP')),
|
||||
('oauth', _('IMAP OAUTH')),
|
||||
('local', _('Local Directory'))),
|
||||
blank=True,
|
||||
null=True,
|
||||
|
@ -249,3 +249,14 @@ HELPDESK_FULL_FIRST_MESSAGE_FROM_EMAIL = getattr(
|
||||
# (which gets stripped/corrupted otherwise)
|
||||
HELPDESK_ALWAYS_SAVE_INCOMING_EMAIL_MESSAGE = getattr(
|
||||
settings, "HELPDESK_ALWAYS_SAVE_INCOMING_EMAIL_MESSAGE", False)
|
||||
|
||||
#######################
|
||||
# email OAUTH #
|
||||
#######################
|
||||
|
||||
HELPDESK_OAUTH = {
|
||||
"token_url": "",
|
||||
"client_id": "",
|
||||
"secret": "",
|
||||
"scope": [""]
|
||||
}
|
||||
|
@ -12,3 +12,5 @@ pinax_teams
|
||||
djangorestframework
|
||||
django-model-utils
|
||||
django-cleanup
|
||||
requests
|
||||
requests_oauthlib
|
||||
|
Loading…
Reference in New Issue
Block a user