from fastcore.test import test_eqMarkdownMerge
Utility functions
get_addr
get_addr (email, name=None)
Convert email and optional name into an email Address object
Specify from_addr and to_addrs as either a string, or an Address object (created with get_addr). Note the to_addrs is a list.
from_addr = get_addr('from@example.com', 'Jeremy Howard')
to_addrs = [get_addr('to@example.com', 'Jeręmy Hòwärd')]
print(from_addr)
print(to_addrs[0])Jeremy Howard <from@example.com>
Jeręmy Hòwärd <to@example.com>
attach_file
attach_file (msg, f)
Attach file f to message msg
msg = MIMEMultipart(policy=EmailPolicy())
attach_file(msg, '../settings.ini')
part = msg.get_payload()[0]
test_eq(part.get_content_type(), 'application/octet-stream')
test_eq(part['Content-Disposition'], 'attachment; filename=settings.ini')
assert len(part.get_payload())>20create_multipart_msg
create_multipart_msg (subj, from_addr, to_addrs, md=None, html=None, attach=None, hdrs=None)
Create a multipart email with markdown text and HTML
msg = create_multipart_msg('Test Subject', from_addr, to_addrs, hdrs={'atest':'foo'},
md='**Bold text**', html='<b>Bold text</b>')
test_eq(msg['Subject'], 'Test Subject')
test_eq(msg['From'], str(from_addr))
test_eq(msg['atest'], 'foo')
test_eq(len(msg.get_payload()), 2)
test_eq(msg.get_payload()[0].get_content_type(), 'text/plain')
test_eq(msg.get_payload()[1].get_content_type(), 'text/html')
assert '@' in msg['To']md2email
md2email (subj, from_addr, to_addrs, md, attach=None, hdrs=None)
Create a multipart email from markdown
test_msg2 = md2email('Test md2email', 'support@answer.ai', 'j@answer.ai', '**Markdown** test with _attachment_', attach='../settings.ini')
test_eq(test_msg2['Subject'], 'Test md2email')
payload = test_msg2.get_payload()
test_eq(len(payload), 3)
test_eq(payload[2]['Content-Disposition'], 'attachment; filename=settings.ini')The basic email body is the plain text message (note that the template variables in {} will be filled in by MarkdownMerge):
print(payload[0].get_payload())**Markdown** test with _attachment_
Most email software is set up to display the HTML version:
from IPython.display import HTMLhtml = payload[1].get_payload()
HTML(html)Markdown test with attachment
att = payload[2].get_payload()import base64decoded = base64.b64decode(payload[2].get_payload())
print(decoded.decode('utf-8')[:35])[DEFAULT]
repo = markdown_merge
lib
smtp_connection
smtp_connection (host, port, user=None, password=None, use_ssl=True, use_tls=False)
Create and return an SMTP connection
servernm='email-smtp.us-west-2.amazonaws.com'
username=os.getenv('SES_SMTP_USER')
password=os.getenv('SES_SMTP_PASS')smtp_cfg = dict(host=servernm, port=587, user=username, password=password, use_ssl=False, use_tls=True)
test_msg = create_multipart_msg('Test from stdlib', 'support@answer.ai', 'j@answer.ai', md='**Test message**', html='<b>Test message</b>')
# try:
# conn = smtp_connection(**smtp_cfg)
# conn.send_message(test_msg)
# finally: conn.quit()MarkdownMerge
MarkdownMerge (addrs, from_addr, subj, msg, smtp_cfg=None, inserts=None, test=False, hdrs=None, env_from=None)
Send templated email merge messages formatted with Markdown
Your message should be in markdown format. It will be converted into a two part email, containing both a plain text and an HTML part, so recipients will see whatever format they’re set as their preference for viewing mail. Anything in curly brackets {} will be replaced with the contents of the inserts dictionary for that address. If there are no bracketed variables to replace, then you don’t need to pass any inserts.
msg = "**Hello {name}!**\n\nYour special number is: *{num}*"inserts is a list of dictionaries. For each dictionary, the keys should match the bracketed names in your email template, and the values will be filled in to those sections.
inserts = [{'name': 'Jeremy', 'num': 42}, {'name': 'Rachel', 'num': 7}]mm = MarkdownMerge(['aaa@answer.ai', 'bbb@answer.ai'], 'from@answer.ai', 'Test merge',
msg, smtp_cfg=smtp_cfg, inserts=inserts, test=True)mm.send_msgs()To: aaa@answer.ai
----------------------------------------
**Hello Jeremy!**
Your special number is: *42*
========================================
To: bbb@answer.ai
----------------------------------------
**Hello Rachel!**
Your special number is: *7*
========================================
Use pause to avoid sending too many messages too quickly; many SMTP servers restrict sending speed to avoid abuse. If you get an error during sending (e.g. “too many messages”), then wait an hour or so, then continue sending, using a larger pause value.
NB: You can just call send_msgs again when resending, since the successfully sent message count is saved, and those messages are not re-sent (unless you call reset). This includes test sends, therefore you should run reset after a test send.
To reset the counter to 0, call reset:
mm.reset()