Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

opt: email account support oauth #667

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 132 additions & 0 deletions dtable_events/dtable_io/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import requests
import smtplib
import msal
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import formataddr, parseaddr
Expand Down Expand Up @@ -720,6 +721,137 @@ def send_email_msg(auth_info, send_info, username, config=None, db_session=None)
session.close()
return result

def _get_oauth_smtp_headers(client_id, client_secret, authority, scopes):
app = msal.ConfidentialClientApplication(
client_id,
authority=authority,
client_credential=client_secret,
)
result = app.acquire_token_for_client(scopes=scopes.replace(' ','').split(','))
if "access_token" in result:
headers = {
'Authorization': f'Bearer {result["access_token"]}',
'Content-Type': 'application/json'
}
return headers

else:
raise Exception('Failed to acquire token', result.get('error'), result.get('error_description'))

def send_email_msg_by_oauth_auth(auth_info, send_info, username, config=None, db_session=None):
# auth info
host_user = auth_info.get('host_user')
client_id = auth_info.get('client_id', '')
client_secret = auth_info.get('client_secret', '')
authority = auth_info.get('authority', '')
scopes = auth_info.get('scopes', '')
endpoint = auth_info.get('endpoint', '')
sender_name = auth_info.get('sender_name', '')
sender_email = auth_info.get('sender_email', '')

# send info
msg = send_info.get('message', '')
html_msg = send_info.get('html_message', '')
send_to = send_info.get('send_to', [])
subject = send_info.get('subject', '')
copy_to = send_info.get('copy_to', [])
reply_to = send_info.get('reply_to', '')
file_download_urls = send_info.get('file_download_urls', None)
message_id = send_info.get('message_id', '')

result = {}
if not msg and not html_msg:
result['err_msg'] = 'Email message invalid'
return result

try:
headers = _get_oauth_smtp_headers(client_id, client_secret, authority, scopes)
except Exception as e:
dtable_message_logger.warning(f'SMTP auth failure: {e}')
result['err_msg'] = 'SMTP auth failure'
return result

email_data = {
'message':{
'subject': subject,
},
'body': {
'contentType': 'html' if html_msg else 'text',
'content': html_msg if html_msg else msg
},
'from':{
'emailAddress': {
'address': sender_email if sender_name else host_user
}
},
'toRecipients': [
{
'emailAddress':{
'address': to
}
}
for to in send_to
],
'ccRecipients': [
{
'emailAddress':{
'address': to
}
}
for to in copy_to
],
'replyTo':[
{
'emailAddress':{
'address': to
}
}
for to in reply_to
]
}

if sender_name:
email_data['from']['emailAddress']['name'] = sender_name

if message_id:
email_data.update({'internetMessageId': message_id})

if file_download_urls:
email_data.update({'attachments':[
{
'@odata.type': '#microsoft.graph.fileAttachment',
'name': 'UTF-8\'\'' + parse.quote(file_name),
'contentType': 'application/octet-stream',
'contentBytes': requests.get(file_url).content
}
for file_name, file_url in file_download_urls.items()
]})

try:
response = requests.post(
endpoint,
headers=headers,
data=json.dumps(email_data)
)
if response.status_code != 202:
raise Exception(f'Error sending email: {response.status_code} - {response.text}')
success = True
except Exception as e:
dtable_message_logger.warning(e)
result['err_msg'] = e
else:
dtable_message_logger.info('Email sending success!')

session = db_session or init_db_session_class(config)()
try:
save_email_sending_records(session, username, endpoint, success)
except Exception as e:
dtable_message_logger.error(
'Email sending log record error: %s' % e)
finally:
session.close()
return result


def batch_send_email_msg(auth_info, send_info_list, username, config=None, db_session=None):
"""
Expand Down
34 changes: 25 additions & 9 deletions dtable_events/dtable_io/request_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -585,14 +585,30 @@ def add_email_sending_task():
if image_cid_url_map and not isinstance(image_cid_url_map, dict):
image_cid_url_map = json.loads(image_cid_url_map)

auth_info = {
'email_host': data.get('email_host'),
'email_port': data.get('email_port'),
'host_user': data.get('host_user'),
'password': data.get('password'),
'sender_name': data.get('sender_name'),
'sender_email': data.get('sender_email')
}
auth_type = data.get('auth_type')

if auth_type == 'LOGIN':
auth_info = {
'email_host': data.get('email_host'),
'email_port': data.get('email_port'),
'host_user': data.get('host_user'),
'password': data.get('password'),
'sender_name': data.get('sender_name'),
'sender_email': data.get('sender_email')
}
elif auth_type == 'OAUTH':
auth_info = {
'host_user': data.get('host_user'),
'client_id': data.get('client_id'),
'client_secret': data.get('client_secret'),
'authority': data.get('authority'),
'scopes': data.get('scopes'),
'endpoint': data.get('endpoint'),
'sender_name': data.get('sender_name'),
'sender_email': data.get('sender_email')
}
else:
return make_response(('Bad request', 400))

send_info = {
'message': data.get('message'),
Expand All @@ -610,7 +626,7 @@ def add_email_sending_task():

try:
task_id = message_task_manager.add_email_sending_task(
auth_info, send_info, username)
auth_type, auth_info, send_info, username)
except Exception as e:
logger.error(e)
return make_response((e, 500))
Expand Down
9 changes: 6 additions & 3 deletions dtable_events/dtable_io/task_message_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,13 @@ def init(self, workers, file_server_port, io_task_timeout, config):
def is_valid_task_id(self, task_id):
return task_id in self.tasks_map.keys()

def add_email_sending_task(self, auth_info, send_info, username):
from dtable_events.dtable_io import send_email_msg
def add_email_sending_task(self, auth_type, auth_info, send_info, username):
from dtable_events.dtable_io import send_email_msg, send_email_msg_by_oauth_auth
task_id = str(uuid.uuid4())
task = (send_email_msg,(auth_info, send_info, username, self.config))
if auth_type == 'LOGIN':
task = (send_email_msg,(auth_info, send_info, username, self.config))
elif auth_type == 'OAUTH':
task = (send_email_msg_by_oauth_auth,(auth_info, send_info, username, self.config))
self.tasks_queue.put(task_id)
self.tasks_map[task_id] = task
return task_id
Expand Down
Loading