def test_cc(): email = EmailMessage('Subject', 'Content', '*****@*****.**', '*****@*****.**', cc='*****@*****.**') message = email.message() assert message['Cc'] == '*****@*****.**' assert email.get_recipients() == ['*****@*****.**', '*****@*****.**']
def test_dont_base64_encode(): """Shouldn't use Base64 encoding at all. """ email = EmailMessage('Subject', 'UTF-8 encoded body', '*****@*****.**', '*****@*****.**', headers={'From': '*****@*****.**'}) assert 'Content-Transfer-Encoding: base64' not in email.as_string()
def test_space_continuation(): """Test for space continuation character in long (ascii) subject headers. """ email = EmailMessage('Long subject lines that get wrapped should use a space continuation character to get expected behaviour in Outlook and Thunderbird', 'Content', '*****@*****.**', '*****@*****.**') message = email.message() assert message['Subject'] == 'Long subject lines that get wrapped should use a space continuation\n character to get expected behaviour in Outlook and Thunderbird'
def test_dont_mangle_from_in_body(): """Make sure that EmailMessage doesn't mangle 'From' in message body.""" email = EmailMessage( 'Subject', 'From the future', '*****@*****.**', '*****@*****.**', headers={'From': '*****@*****.**'}) str_email = email.as_bytes() print(str_email) assert b'>From the future' not in str_email
def test_from_header(): """Make sure we can manually set the From header. """ email = EmailMessage('Subject', 'Content', '*****@*****.**', '*****@*****.**', headers={'From': '*****@*****.**'}) message = email.message() assert message['From'] == '*****@*****.**'
def test_multiple_cc_and_to(): email = EmailMessage('Subject', 'Content', '*****@*****.**', to=['*****@*****.**', '*****@*****.**'], cc=['*****@*****.**', '*****@*****.**']) message = email.message() assert message['Cc'] == '[email protected], [email protected]' assert email.get_recipients() == ['*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**']
def test_ascii(): email = EmailMessage('Subject', 'Content', '*****@*****.**', '*****@*****.**') message = email.render() assert message['Subject'] == 'Subject' assert message.get_payload() == 'Content' assert message['From'] == '*****@*****.**' assert message['To'] == '*****@*****.**'
def test_cc(): email = EmailMessage('Subject', 'Content', '*****@*****.**', cc='*****@*****.**') message = email.render() assert message['Cc'] == '*****@*****.**' assert not message['To'] assert not message['Bcc'] assert email.get_recipients() == ['*****@*****.**']
def test_multiple_recipients(): email = EmailMessage('Subject', 'Content', '*****@*****.**', ['*****@*****.**', '*****@*****.**']) message = email.render() assert message['Subject'] == 'Subject' assert message.get_payload() == 'Content' assert message['From'] == '*****@*****.**' assert message['To'] == ('[email protected], [email protected]')
def test_multiple_bcc(): email = EmailMessage('Subject', 'Content', '*****@*****.**', bcc=['*****@*****.**', '*****@*****.**']) message = email.render() assert not message['To'] assert not message['Cc'] assert not message['Bcc'] # as it should assert email.get_recipients() == ['*****@*****.**', '*****@*****.**']
def test_message_header_overrides(): """Specifying dates or message-ids in the extra headers overrides the default values. """ headers = {'date': 'Fri, 09 Nov 2001 01:08:47 -0000', 'Message-ID': 'foo'} email = EmailMessage('Subject', 'Content', '*****@*****.**', '*****@*****.**', headers=headers) assert email.as_string() == 'Content-Type: text/plain; charset="utf-8"\nMIME-Version: 1.0\nContent-Transfer-Encoding: 7bit\nSubject: Subject\nFrom: [email protected]\nTo: [email protected]\ndate: Fri, 09 Nov 2001 01:08:47 -0000\nMessage-ID: foo\n\nContent'
def test_invalid_destination(): dest = 'toБ@example.com' email = EmailMessage('Subject', 'Content', '*****@*****.**', dest) message = email.render() assert message['Subject'] == 'Subject' assert message.get_payload() == 'Content' assert message['From'] == '*****@*****.**' assert message['To'] != dest
def test_multiple_cc(): email = EmailMessage('Subject', 'Content', '*****@*****.**', cc=['*****@*****.**', '*****@*****.**']) message = email.render() print(message['Cc']) assert message['Cc'] == '[email protected], [email protected]' assert not message['To'] assert not message['Bcc'] assert email.get_recipients() == ['*****@*****.**', '*****@*****.**']
def test_multiple_replyto(): email = EmailMessage('Subject', 'Content', '*****@*****.**', reply_to=['*****@*****.**', '*****@*****.**']) message = email.render() assert message['Reply-To'] == '[email protected], [email protected]' assert not message['To'] assert not message['Cc'] assert not message['Bcc'] # as it should assert email.get_recipients() == []
def test_recipients_as_tuple(): email = EmailMessage('Subject', 'Content', '*****@*****.**', to=('*****@*****.**', '*****@*****.**'), cc=('*****@*****.**', '*****@*****.**'), bcc=('*****@*****.**',)) message = email.message() assert message['Cc'] == '[email protected], [email protected]' assert email.get_recipients() == ['*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**']
def test_7bit_no_quoted_printable(): """Shouldn't use quoted printable, should detect it can represent content with 7 bit data. """ email = EmailMessage('Subject', 'Body with only ASCII characters.', '*****@*****.**', '*****@*****.**', headers={'From': '*****@*****.**'}) msg = email.as_string() assert 'Content-Transfer-Encoding: quoted-printable' not in msg assert 'Content-Transfer-Encoding: 7bit' in msg
def test_multiple_message_call(): """Make sure that headers are not changed when calling `EmailMessage.render()` again. """ email = EmailMessage('Subject', 'Content', '*****@*****.**', '*****@*****.**', headers={'From': '*****@*****.**'}) message = email.render() assert message['From'] == '*****@*****.**' message = email.render() assert message['From'] == '*****@*****.**'
def test_unicode_headers(): headers = { 'Sender': '"Firstname Sürname" <*****@*****.**>', 'Comments': 'My Sürname is non-ASCII', } email = EmailMessage(u"Gżegżółka", "Content", "*****@*****.**", "*****@*****.**", headers=headers) message = email.render() assert message['Subject'] == '=?utf-8?b?R8W8ZWfFvMOzxYJrYQ==?=' assert message['Sender'] == '=?utf-8?q?Firstname_S=C3=BCrname?= <*****@*****.**>' assert message['Comments'] == '=?utf-8?q?My_S=C3=BCrname_is_non-ASCII?='
def test_unicode_address_header(): """When a to/from/cc header contains unicode, make sure the email addresses are parsed correctly (especially with regards to commas). """ email = EmailMessage('Subject', 'Content', '*****@*****.**', ['"Firstname Sürname" <*****@*****.**>', '*****@*****.**']) message = email.message() assert message['To'] == '=?utf-8?q?Firstname_S=C3=BCrname?= <*****@*****.**>, [email protected]' email = EmailMessage('Subject', 'Content', '*****@*****.**', ['*****@*****.**', '"Sürname, Firstname" <*****@*****.**>']) message = email.message() assert message['To'] == '[email protected], =?utf-8?q?S=C3=BCrname=2C_Firstname?= <*****@*****.**>'
def test_multiple_to_cc_bcc(): email = EmailMessage('Subject', 'Content', '*****@*****.**', to=['*****@*****.**', '*****@*****.**'], cc=['*****@*****.**', '*****@*****.**'], bcc=['*****@*****.**', '*****@*****.**']) message = email.render() assert message['To'] == '[email protected], [email protected]' assert message['Cc'] == '[email protected], [email protected]' assert message['Bcc'] == '[email protected], [email protected]' assert email.get_recipients() == [ '*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**', ]
def test_safe_mime_multipart(): """Make sure headers can be set with a different encoding than utf-8 in SafeMIMEMultipart as well """ subject = 'Message from Firstname Sürname' from_email = '*****@*****.**' to = '"Sürname, Firstname" <*****@*****.**>' text_content = 'This is an important message.' html_content = '<p>This is an <strong>important</strong> message.</p>' headers = {"Date": "Fri, 09 Nov 2001 01:08:47 -0000", "Message-ID": "foo"} email = EmailMessage(subject, text_content, from_email, to, html_content=html_content, headers=headers) email.encoding = 'iso-8859-1' email.render()
def test_html(): subject = 'hello' from_email = '*****@*****.**' to = '*****@*****.**' text_content = 'This is an important message.' html_content = '<p>This is an <strong>important</strong> message.</p>' email = EmailMessage(subject, text_content, from_email, to, html_content=html_content) message = email.render() assert message.is_multipart() assert message.get_content_type() == 'multipart/alternative' assert message.get_default_type() == 'text/plain' assert message.get_payload(0).get_content_type() == 'text/plain' assert message.get_payload(1).get_content_type() == 'text/html'
def test_attachments(): subject = 'hello' from_email = '*****@*****.**' to = '*****@*****.**' text_content = 'This is an important message.' html_content = '<p>This is an <strong>important</strong> message.</p>' email = EmailMessage(subject, text_content, from_email, to, html_content=html_content) email.attach('an attachment.pdf', '%PDF-1.4.%...', mimetype='application/pdf') message = email.render() assert message.is_multipart() assert message.get_content_type() == 'multipart/mixed' assert message.get_default_type() == 'text/plain' assert message.get_payload(0).get_content_type() == 'multipart/alternative' assert message.get_payload(1).get_content_type() == 'application/pdf'
def test_recipients_as_tuple(): email = EmailMessage('Subject', 'Content', '*****@*****.**', to=('*****@*****.**', '*****@*****.**'), cc=('*****@*****.**', '*****@*****.**'), bcc=('*****@*****.**', )) message = email.render() assert message['To'] == '[email protected], [email protected]' assert message['Cc'] == '[email protected], [email protected]' assert not message['Bcc'] # as it should assert email.get_recipients() == [ '*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**', ]
def test_sending_unicode(): global smtp_server smtp_server.flush_sink() mailer = SMTPMailer(host='127.0.0.1', port=8000, use_tls=False) email = EmailMessage(u'Olé', u'Contenido en español', u'*****@*****.**', u'toБ@example.com') assert mailer.send_messages(email) sink = smtp_server.sink assert len(sink) == 1
def test_multiple_to_cc_bcc(): email = EmailMessage('Subject', 'Content', '*****@*****.**', to=['*****@*****.**', '*****@*****.**'], cc=['*****@*****.**', '*****@*****.**'], bcc=['*****@*****.**', '*****@*****.**']) message = email.render() assert message['To'] == '[email protected], [email protected]' assert message['Cc'] == '[email protected], [email protected]' assert not message['Bcc'] # as it should assert email.get_recipients() == [ '*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**', '*****@*****.**', ]
def test_8bit_no_quoted_printable(): """Shouldn't use quoted printable, should detect it can represent content with 8 bit data. """ email = EmailMessage('Subject', 'Body with latin characters: àáä.', '*****@*****.**', '*****@*****.**', headers={'From': '*****@*****.**'}) msg = email.as_string() assert 'Content-Transfer-Encoding: quoted-printable' not in msg assert 'Content-Transfer-Encoding: 8bit' in msg email = EmailMessage('Subject', u'Body with non latin characters: А Б В Г Д Е Ж Ѕ З И І К Л М Н О П.', '*****@*****.**', '*****@*****.**', headers={'From': '*****@*****.**'}) msg = email.as_string() assert 'Content-Transfer-Encoding: quoted-printable' not in msg assert 'Content-Transfer-Encoding: 8bit' in msg
def test_encoding(): """Encode body correctly with other encodings than utf-8 """ email = EmailMessage('Subject', 'Firstname Sürname is a great guy.', '*****@*****.**', '*****@*****.**') email.encoding = 'iso-8859-1' message = email.message() assert message.as_string().startswith('Content-Type: text/plain; charset="iso-8859-1"\nMIME-Version: 1.0\nContent-Transfer-Encoding: quoted-printable\nSubject: Subject\nFrom: [email protected]\nTo: [email protected]') assert message.get_payload() == 'Firstname S=FCrname is a great guy.' # Make sure MIME attachments also works correctly with other encodings than utf-8 text_content = 'Firstname Sürname is a great guy.' html_content = '<p>Firstname Sürname is a <strong>great</strong> guy.</p>' email = EmailMessage('Subject', text_content, '*****@*****.**', '*****@*****.**', html_content=html_content) email.encoding = 'iso-8859-1' message = email.message() assert message.get_payload(0).as_string() == \ 'Content-Type: text/plain; charset="iso-8859-1"\nMIME-Version: 1.0\nContent-Transfer-Encoding: quoted-printable\n\nFirstname S=FCrname is a great guy.' assert message.get_payload(1).as_string() == \ 'Content-Type: text/html; charset="iso-8859-1"\nMIME-Version: 1.0\nContent-Transfer-Encoding: quoted-printable\n\n<p>Firstname S=FCrname is a <strong>great</strong> guy.</p>'
def test_encoding(): """Encode body correctly with other encodings than utf-8 """ email = EmailMessage('Subject', 'Firstname Sürname is a great guy.', '*****@*****.**', '*****@*****.**') email.encoding = 'iso-8859-1' message = email.render() assert message.as_string().startswith( 'Content-Type: text/plain; charset="iso-8859-1"' '\nMIME-Version: 1.0' '\nContent-Transfer-Encoding: quoted-printable' '\nSubject: Subject' '\nFrom: [email protected]' '\nTo: [email protected]') assert message.get_payload() == 'Firstname S=FCrname is a great guy.' # Make sure MIME attachments also works correctly with other encodings than utf-8 text_content = 'Firstname Sürname is a great guy.' html_content = '<p>Firstname Sürname is a <strong>great</strong> guy.</p>' email = EmailMessage('Subject', text_content, '*****@*****.**', '*****@*****.**', html_content=html_content) email.encoding = 'iso-8859-1' message = email.render() assert message.get_payload(0).as_string() == ( 'Content-Type: text/plain; charset="iso-8859-1"' '\nMIME-Version: 1.0' '\nContent-Transfer-Encoding: quoted-printable' '\n\nFirstname S=FCrname is a great guy.') assert message.get_payload(1).as_string() == ( 'Content-Type: text/html; charset="iso-8859-1"' '\nMIME-Version: 1.0' '\nContent-Transfer-Encoding: quoted-printable' '\n\n<p>Firstname S=FCrname is a <strong>great</strong> guy.</p>')
def test_batch_too_many_recipients(): global smtp_server smtp_server.flush_sink() mailer = SMTPMailer(host='127.0.0.1', port=8000, use_tls=False, max_recipients=200) send_to = ['user{}@example.com'.format(i) for i in range(1, 1501)] msg = EmailMessage('The Subject', 'Content', '*****@*****.**', send_to) assert mailer.send_messages(msg) == 1 sink = smtp_server.sink assert len(sink) == 8 assert len(sink[0].get('to').split(',')) == 200 assert len(sink[1].get('to').split(',')) == 200 assert len(sink[2].get('to').split(',')) == 200 assert len(sink[3].get('to').split(',')) == 200 assert len(sink[4].get('to').split(',')) == 200 assert len(sink[5].get('to').split(',')) == 200 assert len(sink[6].get('to').split(',')) == 200 assert len(sink[7].get('to').split(',')) == 100
def test_unicode_address_header(): """When a to/from/cc header contains unicode, make sure the email addresses are parsed correctly (especially with regards to commas). """ email = EmailMessage( 'Subject', 'Content', '*****@*****.**', ['"Firstname Sürname" <*****@*****.**>', '*****@*****.**']) message = email.render() assert message[ 'To'] == '=?utf-8?q?Firstname_S=C3=BCrname?= <*****@*****.**>, [email protected]' email = EmailMessage( 'Subject', 'Content', '*****@*****.**', ['*****@*****.**', '"Sürname, Firstname" <*****@*****.**>']) message = email.render() assert message[ 'To'] == '[email protected], =?utf-8?q?S=C3=BCrname=2C_Firstname?= <*****@*****.**>'
def test_8bit_no_quoted_printable(): """Shouldn't use quoted printable, should detect it can represent content with 8 bit data. """ email = EmailMessage('Subject', 'Body with latin characters: àáä.', '*****@*****.**', '*****@*****.**', headers={'From': '*****@*****.**'}) msg = email.as_string() assert 'Content-Transfer-Encoding: quoted-printable' not in msg assert 'Content-Transfer-Encoding: 8bit' in msg email = EmailMessage( 'Subject', u'Body with non latin characters: А Б В Г Д Е Ж Ѕ З И І К Л М Н О П.', '*****@*****.**', '*****@*****.**', headers={'From': '*****@*****.**'}) msg = email.as_string() assert 'Content-Transfer-Encoding: quoted-printable' not in msg assert 'Content-Transfer-Encoding: 8bit' in msg
def test_header_injection(): email = EmailMessage('Subject\nInjection Test', 'Content', '*****@*****.**', '*****@*****.**') with pytest.raises(ValueError): email.render()
def make_emails(): return [ EmailMessage('Subject-%s' % num, 'Content', '*****@*****.**', '*****@*****.**') for num in range(1, 5) ]
def make_emails(): return [ EmailMessage('Subject', 'Content #%s' % content, '*****@*****.**', '*****@*****.**') for content in range(1, 5) ]
def mail_report(name, recipients=None, stdout=False, template=None): reports_dir = ConfigDir().sub('reports').path config = Config.load_default() template_dir = ConfigDir().sub('templates').path template_name = template or config.mailing.default_template if not template_name.endswith('.html'): template_name += '.html' loader = ChoiceLoader([ FileSystemLoader(template_dir), PackageLoader('athena.broadcasting', 'templates') ]) env = Environment(loader=loader) template = env.get_template(template_name) job_file = path_join(reports_dir, name) if not isfile(job_file): raise ValueError( "{} does not exist or is not a readable file!".format(name)) with open(job_file, 'r') as f: job = yaml.load(f.read()) title = job.get('title') description = job.get('description') data = job.get('data') inline_blocks = data.get('inline') csv_items = data.get('csv') today = datetime.now().date().strftime('%d %b %Y') if not recipients: job_recepients = job.get('recipients') recipients = [ recipient.strip() for recipient in job_recepients.split(',') ] if job_recepients else None if not data or (not inline_blocks and not csv_items): raise ValueError( "Your job config must contain a 'data' section with one or more inline or csv entries" ) if not recipients and not stdout: raise ValueError("No recipients to send the data!") blocks = [] if inline_blocks: for block_item in inline_blocks: block = { 'name': block_item['name'], 'description': block_item['description'] } if block_item['type'] == 'sql': rows, headers = query_impala(block_item['query']) block['data'] = {'headers': headers, 'rows': rows} else: raise ValueError( "{} contains an inline block of unknown type ({})!".format( name, block_item['type'])) blocks.append(block) csvs = [] if csv_items: tmpdir = create_tmp_dir(prefix=slugify(title, separator='_')) for item in csv_items: filenameretrieve = item['filename'] csv_path = path_join(tmpdir, filenameretrieve) if item['type'] == 'sql': sql_query = item['query'] if 'with_items' in item: variables = item['with_items'] for variable in variables: processed_sql_query = sql_query.replace( "{{ item }}", variable) processed_filename = filenameretrieve.replace( "{{ item }}", variable) csv_path_instance = path_join(tmpdir, processed_filename) query_to_csv(processed_sql_query, csv_path_instance) csvs.append({ 'name': processed_filename, 'path': csv_path_instance }) else: query_to_csv(sql_query, csv_path) csvs.append({'name': filenameretrieve, 'path': csv_path}) else: raise ValueError( "{} contains csv item of unknown type ({})!".format( name, item['type'])) html = template.render(title=title, description=description, today=today, blocks=blocks) if stdout: print html print "\n" for c in csvs: print c else: mailer = SMTPMailer(host=config.mailing.smtp_host, port=config.mailing.smtp_port, username=config.mailing.smtp_username, password=config.mailing.smtp_password, use_tls=config.mailing.smtp_use_tls) email_msg = EmailMessage(subject="{title} {date}".format(title=title, date=today), text="This mail can only be viewed as HTML", from_email=config.mailing.from_address, to=recipients, html=html) for c in csvs: email_msg.attach_file(c['path']) mailer.send_messages(email_msg)