Skip to content

Instantly share code, notes, and snippets.

@matt-blodgett
Created July 2, 2019 23:09
Show Gist options
  • Save matt-blodgett/0a95e07256d6b7df7c1e35c85fb460b0 to your computer and use it in GitHub Desktop.
Save matt-blodgett/0a95e07256d6b7df7c1e35c85fb460b0 to your computer and use it in GitHub Desktop.
from typing import Union
import logging
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email import encoders
LOG = logging.getLogger(__name__)
SMTP_DEBUG_LEVEL = 0 # 0 == off, 1 == debug, 2 == timestamps
SMTP_HOST = 'smtp.gmail.com'
SMTP_PORT = 587
SMTP_USER = ''
SMTP_PASSWORD = ''
def _log_success(method, response):
resp_code, resp_msg = response
# LOG.info(f'SMTP: SUCCESS <{method}: {{code={resp_code}, message={resp_msg}}}>')
print(f'SMTP: SUCCESS <{method}: {{code={resp_code}, message={resp_msg}}}>')
def _log_failure(error):
err_cls = error.__class__.__name__
err_code, err_msg = error.args
LOG.error(f'SMTP: FAILURE <smtplib.{err_cls} {{code={err_code}, message={err_msg}}}>')
def _fail_safely(func):
def _try_and_catch(*args, **kwargs):
try:
return func(*args, **kwargs)
except smtplib.SMTPException as e:
_log_failure(e)
return False
return _try_and_catch
class Email:
def __init__(self, sender=SMTP_USER, password=SMTP_PASSWORD, host=SMTP_HOST, port=SMTP_PORT):
self.sender = sender
self.password = password
self.host = host
self.port = port
self.subject = None
self.body = None
self.attachments = []
self.message = MIMEMultipart()
def set_message(self, subject: Union[str, None], body: Union[str, None], html=False) -> None:
self.subject = subject
if body is None:
self.body = None
else:
self.body = MIMEText(body, 'plain' if not html else 'html')
def add_attachment(self, data: bytes, filename: str, mimetype=r'application\octet-stream') -> MIMEBase:
attachment = MIMEBase(*mimetype.split('\\'))
attachment.set_payload(data)
encoders.encode_base64(attachment)
attachment.add_header('Content-Disposition', f'attachment; filename="{filename}"')
self.attachments.append(attachment)
return attachment
@_fail_safely
def send(self, recipients: Union[str, list, tuple], cc=None, bcc=None) -> bool:
self.message['Subject'] = self.subject
self.message['From'] = self.sender
self.message['To'] = recipients
self.message['Cc'] = cc
self.message['Bcc'] = bcc
if self.body is not None:
self.message.attach(self.body)
for attachment in self.attachments:
self.message.attach(attachment)
print(f'SMTP: Creating TLS SMTP client {{host={self.host}, port={self.port}}}')
with smtplib.SMTP(self.host, self.port) as smtp_client:
smtp_client.set_debuglevel(SMTP_DEBUG_LEVEL)
print(f'SMTP: Sending Email {{sender={self.sender}, recipients={recipients}, cc={cc}, bcc={bcc}}}')
response = smtp_client.starttls()
_log_success('starttls', response)
response = smtp_client.login(self.sender, self.password)
_log_success('login', response)
smtp_client.send_message(self.message)
LOG.info('SMTP: SUCCESS <send: Email sent successfully>')
print('SMTP: SUCCESS <send: Email sent successfully>')
self.subject = None
self.body = None
self.attachments = []
self.message = MIMEMultipart()
return True
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment