Skip to content

Commit

Permalink
feat: SMTP as a fallback function when Sendgrid quota exceeds limit (#…
Browse files Browse the repository at this point in the history
…5981)

Modified arguments placement

Corrected quota info

Sent email and handled error

Cease email service if SMTP not configured

fix travis

divided into two tasks

changed logger message and smtp fallback
  • Loading branch information
mrsaicharan1 authored and iamareebjamal committed Jun 20, 2019
1 parent 47363b9 commit c10a3fc
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 65 deletions.
84 changes: 52 additions & 32 deletions app/api/helpers/mail.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import base64
import logging
from datetime import datetime

from flask import current_app
Expand All @@ -16,10 +17,28 @@
from app.models.user import User


def check_smtp_config(smtp_encryption):
"""
Checks config of SMTP
"""
config = {
'host': get_settings()['smtp_host'],
'username': get_settings()['smtp_username'],
'password': get_settings()['smtp_password'],
'encryption': smtp_encryption,
'port': get_settings()['smtp_port'],
}
for field in config:
if field is None:
return False
return True


def send_email(to, action, subject, html, attachments=None):
"""
Sends email and records it in DB
"""
from .tasks import send_email_task_sendgrid, send_email_task_smtp
if not string_empty(to):
email_service = get_settings()['email_service']
email_from_name = get_settings()['email_from_name']
Expand All @@ -36,40 +55,41 @@ def send_email(to, action, subject, html, attachments=None):
}

if not current_app.config['TESTING']:
if email_service == 'smtp':
smtp_encryption = get_settings()['smtp_encryption']
if smtp_encryption == 'tls':
smtp_encryption = 'required'
elif smtp_encryption == 'ssl':
smtp_encryption = 'ssl'
elif smtp_encryption == 'tls_optional':
smtp_encryption = 'optional'
else:
smtp_encryption = 'none'

config = {
'host': get_settings()['smtp_host'],
'username': get_settings()['smtp_username'],
'password': get_settings()['smtp_password'],
'encryption': smtp_encryption,
'port': get_settings()['smtp_port'],
}

from .tasks import send_mail_via_smtp_task
send_mail_via_smtp_task.delay(config, payload)
smtp_encryption = get_settings()['smtp_encryption']
if smtp_encryption == 'tls':
smtp_encryption = 'required'
elif smtp_encryption == 'ssl':
smtp_encryption = 'ssl'
elif smtp_encryption == 'tls_optional':
smtp_encryption = 'optional'
else:
payload['fromname'] = email_from_name
key = get_settings()['sendgrid_key']
if not key:
print('Sendgrid key not defined')
return
headers = {
"Authorization": ("Bearer " + key),
"Content-Type": "application/json"
}
from .tasks import send_email_task
send_email_task.delay(payload, headers)
smtp_encryption = 'none'

smtp_config = {
'host': get_settings()['smtp_host'],
'username': get_settings()['smtp_username'],
'password': get_settings()['smtp_password'],
'encryption': smtp_encryption,
'port': get_settings()['smtp_port'],
}
smtp_status = check_smtp_config(smtp_encryption)
if smtp_status:
if email_service == 'smtp':
send_email_task_smtp.delay(payload=payload, headers=None, smtp_config=smtp_config)
else:
key = get_settings().get('sendgrid_key')
if key:
headers = {
"Authorization": ("Bearer " + key),
"Content-Type": "application/json"
}
payload['fromname'] = email_from_name
send_email_task_sendgrid.delay(payload=payload, headers=headers, smtp_config=smtp_config)
else:
logging.exception('SMTP & sendgrid have not been configured properly')

else:
logging.exception('SMTP is not configured properly. Cannot send email.')
# record_mail(to, action, subject, html)
mail = Mail(
recipient=to, action=action, subject=subject,
Expand Down
72 changes: 39 additions & 33 deletions app/api/helpers/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from app.models.session import Session
from app.models.speaker import Speaker


"""
Define all API v2 celery tasks here
This is done to resolve circular imports
Expand Down Expand Up @@ -51,58 +52,63 @@
celery = make_celery()


@celery.task(name='send.email.post')
def send_email_task(payload, headers):
message = Mail(from_email=payload['from'],
to_emails=payload['to'],
subject=payload['subject'],
html_content=payload["html"])
if payload['attachments'] is not None:
for attachment in payload['attachments']:
with open(attachment, 'rb') as f:
file_data = f.read()
f.close()
encoded = base64.b64encode(file_data).decode()
attachment = Attachment()
attachment.file_content = FileContent(encoded)
attachment.file_type = FileType('application/pdf')
attachment.file_name = FileName(payload['to'])
attachment.disposition = Disposition('attachment')
message.add_attachment(attachment)
sendgrid_client = SendGridAPIClient(get_settings()['sendgrid_key'])
logging.info('Sending an email regarding {} on behalf of {}'.format(payload["subject"], payload["from"]))
@celery.task(name='send.email.post.sendgrid')
def send_email_task_sendgrid(payload, headers, smtp_config):
try:
message = Mail(from_email=payload['from'],
to_emails=payload['to'],
subject=payload['subject'],
html_content=payload["html"])
if payload['attachments'] is not None:
for attachment in payload['attachments']:
with open(attachment, 'rb') as f:
file_data = f.read()
f.close()
encoded = base64.b64encode(file_data).decode()
attachment = Attachment()
attachment.file_content = FileContent(encoded)
attachment.file_type = FileType('application/pdf')
attachment.file_name = FileName(payload['to'])
attachment.disposition = Disposition('attachment')
message.add_attachment(attachment)
sendgrid_client = SendGridAPIClient(get_settings()['sendgrid_key'])
logging.info('Sending an email regarding {} on behalf of {}'.format(payload["subject"], payload["from"]))
sendgrid_client.send(message)
logging.info('Email sent successfully')
except Exception:
logging.exception('Error occured while sending the email')
except urllib.error.HTTPError as e:
if e.code == 429:
logging.warning("Sendgrid quota has exceeded")
send_email_task_smtp.delay(payload=payload, headers=None, smtp_config=smtp_config)
else:
logging.exception("The following error has occurred with sendgrid-{}".format(str(e)))


@celery.task(name='send.email.post.smtp')
def send_mail_via_smtp_task(config, payload):
def send_email_task_smtp(payload, smtp_config, headers=None):
mailer_config = {
'transport': {
'use': 'smtp',
'host': config['host'],
'username': config['username'],
'password': config['password'],
'tls': config['encryption'],
'port': config['port']
'transport': {
'use': 'smtp',
'host': smtp_config['host'],
'username': smtp_config['username'],
'password': smtp_config['password'],
'tls': smtp_config['encryption'],
'port': smtp_config['port']
}
}
}

mailer = Mailer(mailer_config)
mailer.start()
message = Message(author=payload['from'], to=payload['to'])
message.subject = payload['subject']
message.plain = strip_tags(payload['html'])
message.rich = payload['html']
message.attach(name=payload['attachments'])
if payload['attachments'] is not None:
for attachment in payload['attachments']:
message.attach(name=attachment)
mailer.send(message)
logging.info('Message sent via SMTP')
mailer.stop()


@celery.task(base=RequestContextTask, name='resize.event.images', bind=True)
def resize_event_images_task(self, event_id, original_image_url):
event = safe_query(db, Event, 'id', event_id, 'event_id')
Expand Down

0 comments on commit c10a3fc

Please sign in to comment.