Giter VIP home page Giter VIP logo

python-emails's Introduction

python-emails

Modern python library for email.

Build message:

>>> import emails
>>> message = emails.html(html="<p>Hi!<br>Here is your receipt...",
                       subject="Your receipt No. 567098123",
                       mail_from=('Some Store', '[email protected]'))
>>> message.attach(data=open('bill.pdf', 'rb'), filename='bill.pdf')

send message and get response from smtp server:

>>> r = message.send(to='[email protected]', smtp={'host': 'aspmx.l.google.com', 'timeout': 5})
>>> assert r.status_code == 250

and more:

  • DKIM signature
  • Render body from template
  • Flask extension and Django integration
  • Message body transformation methods
  • Load message from url or from file

Documentation: python-emails.readthedocs.org

Flask extension: flask-emails



https://github.com/lavr/python-emails/workflows/Tests/badge.svg?branch=master https://coveralls.io/repos/lavr/python-emails/badge.svg?branch=master

python-emails's People

Contributors

dalepotter avatar daviey avatar lavr avatar manobeeslaar avatar mck9 avatar pyup-bot avatar smihai avatar sochi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

python-emails's Issues

IOError Bad file descriptor

CentOS 6.8 2.6.32
python 2.7.13
emails (0.5.15) installed via pip

Traceback (most recent call last):
  File "/usr/lib64/python2.7/multiprocessing/process.py", line 258, in _bootstrap
    self.run()
  File "/usr/lib64/python2.7/multiprocessing/process.py", line 114, in run
  File "/usr/lib64/python2.7/multiprocessing/process.py", line 114, in run
    self._target(*self._args, **self._kwargs)
  File "/data/server/server/lib/mail.py", line 104, in send_status_real
  File "/data/server/server/lib/mail.py", line 104, in send_status_real
    send(to, u'[notice]-%s' % title, content, cc, attachs=[full_filename])
  File "/data/server/server/lib/mail.py", line 134, in send
    "port": config.port})
  File "/data/server/lib/python2.7/site-packages/emails/message.py", line 404, in send
    return smtp.sendmail(**params)
  File "/data/server/lib/python2.7/site-packages/emails/backend/smtp/backend.py", line 117, in sendmail
    msg=msg.as_string(),
  File "/data/server/lib/python2.7/site-packages/emails/message.py", line 337, in as_string
  File "/data/server/lib/python2.7/site-packages/emails/message.py", line 337, in as_string
    r = to_native(self.build_message(message_cls=message_cls).as_string())
  File "/data/server/lib/python2.7/site-packages/emails/message.py", line 305, in build_message
  File "/data/server/lib/python2.7/site-packages/emails/message.py", line 305, in build_message
    part = f.mime
  File "/data/server/lib/python2.7/site-packages/emails/store/file.py", line 143, in mime
  File "/data/server/lib/python2.7/site-packages/emails/store/file.py", line 143, in mime
    p.set_payload(to_bytes(self.data))
  File "/data/server/lib/python2.7/site-packages/emails/store/file.py", line 57, in get_data
    return _data.read()
IOError: [Errno 9] Bad file descriptor
close failed in file object destructor:
IOError: [Errno 9] Bad file descriptor[Errno 9] Bad file descriptor

Send unicode file name turns into 'ATT001'

Hi,

is it possible to send a unicode file name?
Let say my file name is "שלום.docx" after sending it will be translated to "ATT00001.docx".

Please let me know if this possible at all.

How to send email with CC

Getting error when I add CC while sending emails.

TypeError: send() got an unexpected keyword argument 'cc'

Provide a convenient way to set Reply-To

Currently, there’s no way to set Reply-To in the same way as To, Cc, or Bcc:

>>> import emails
>>> ivan = ('Иван', '[email protected]')
>>> maria = ('Марья', '[email protected]')
>>> msg = emails.Message(mail_to=[ivan], cc=[maria], text='Hello world!')
>>> print(msg.as_string())
[...]
To: =?utf-8?b?0JjQstCw0L0=?= <[email protected]>
Cc: =?utf-8?b?0JzQsNGA0YzRjw==?= <[email protected]>
[...]
>>> msg = emails.Message(mail_to=[ivan], reply_to=[maria], text='Hello world!')
Traceback (most recent call last):
  File "<ipython-input-13-598375a47f5d>", line 1, in <module>
    msg = emails.Message(mail_to=[ivan], reply_to=[maria], text='Hello world!')
TypeError: __init__() got an unexpected keyword argument 'reply_to'

>>> msg = emails.Message(mail_to=[ivan], headers={'Reply-To': [maria]}, text='Hello world!')
>>> print(msg.as_string())
[...]
Reply-To: ,
To: =?utf-8?b?0JjQstCw0L0=?= <[email protected]>
[...]

A reply_to parameter to emails.Message (and emails.html, etc.) would be nice.

test_send_to_unknown_host fails on Linux

emails/testsuite/smtp/test_smtp_backend.py::test_send_to_unknown_host asserts that the errno is 8, which is BSD’s value for EAI_NONAME. But in GNU libc and in musl it’s −2, so the test fails.

You should probably compare to socket.EAI_NONAME instead. This will probably make if not TRAVIS_CI unnecessary, too. I don’t have a BSD/macOS system handy to check, though.

$ pytest emails/testsuite/smtp/test_smtp_backend.py::test_send_to_unknown_host ========================================================= test session starts =========================================================
platform linux -- Python 3.5.2, pytest-3.1.3, py-1.4.34, pluggy-0.4.0
rootdir: /home/vasiliy/tmp/try-out-emails/python-emails, inifile: setup.cfg
plugins: cov-2.5.1
collected 1 item 

emails/testsuite/smtp/test_smtp_backend.py F

============================================================== FAILURES ===============================================================
______________________________________________________ test_send_to_unknown_host ______________________________________________________

    def test_send_to_unknown_host():
        server = SMTPBackend(host='invalid-server.invalid-domain-42.com', port=2525)
        response = server.sendmail(to_addrs='[email protected]', from_addr='[email protected]', msg=emails.html(**SAMPLE_MESSAGE))
        server.close()
        assert response.status_code is None
        assert isinstance(response.error, IOError)
        assert not response.success
        print("response.error.errno=", response.error.errno)
        if not TRAVIS_CI:
            # IOError: [Errno 8] nodename nor servname provided, or not known
>           assert response.error.errno == 8
E           assert -2 == 8
E            +  where -2 = SMTPConnectNetworkError().errno
E            +    where SMTPConnectNetworkError() = <emails.backend.SMTPResponse status_code=None status_text=None>.error

emails/testsuite/smtp/test_smtp_backend.py:27: AssertionError
-------------------------------------------------------- Captured stdout call ---------------------------------------------------------
response.error.errno= -2
========================================================== warnings summary ===========================================================
None
  [pytest] section in setup.cfg files is deprecated, use [tool:pytest] instead.

-- Docs: http://doc.pytest.org/en/latest/warnings.html
================================================ 1 failed, 1 warnings in 0.10 seconds =================================================

mail_from not valid keyword parameter for Message()

In an attempt to get the sample code working, I got this error:
TypeError: init() got an unexpected keyword argument 'mail_from'

For this code:

import emails

from email.message import Message


m = Message(html="<html><p>Build passed: {{ project_name }} <img src='cid:icon.png'> ...",
                   text="Build passed: {{ project_name }} ...",
                   subject="Passed: {{ project_name }}#{{ build_id }}",
                   mail_from=("CI", "[email protected]")
)
m.attach(filename="icon.png", content_disposition="inline", data=open("icon.png", "rb"))
response = m.send(render={"project_name": "user/project1", "build_id": 121},
                  to='[email protected]',
                  smtp={"host":"localhost", "port": 25})

print "status={}".format(response.status_code)

if response.status_code not in [250, ]:
    # message is not sent, retry later
    print response.status_code

Errors while 'pip-3.3 install emails'

There are two known errors installing emails on python 3.3:

  1. pip-3.3 install lxml failed.
    Reason: you should have the development packages of python-3.3, libxml2, libxslt and zlib installed
    Solution: install that packages.
    On ubuntu run:
    apt-get install zlib1g-dev libxml2-dev libxslt1-dev python3.3-dev
  2. pip-3.3 install chardet failed.
    Reason: It seems that pypi chardet version is broken on python-3.3
    Solution: On ubuntu you can install packaged version (apt-get install python3-chardet). On other distributions you should install chatdet manually (for example, download from http://archive.ubuntu.com/ubuntu/pool/main/p/python3-chardet/python3-chardet_2.0.1.orig.tar.gz, unpack & setup.py install)

html parser breaks some link content

Current html serialization method do some escapes making impossible insert template variables to links:

 >>> HTMLParser('<a href="{{ }}">_</a>').to_string()
 <html><body><a href="%7B%7B%20%7D%7D">_</a></body></html>  

Expected result:

<html><body><a href="{{ }}">_</a></body></html> 

Possible mistake in (clumsy) heuristics for email-list detection

Hi buddiez, I hope you're all doing goodie ^__^

I've seen the heuristics for email list detection, and to be honest I'm a bit surprised: from what I can see, the only thing it does is checking weither the iterable is of length 2, if it's a tuple, and if both email and name are string types (or name is falsey - typically empty string or None I suppose).

However, the second check seems to have a typo in the sense that it re-checks the email against string types:
https://github.com/lavr/python-emails/blob/master/emails/utils.py#L133

Other than that typo, I feel like this logic is either a bit fragile or not sufficiently documented: if name-email pairs should be tuples, the documentation should likely mention it explicitly (I do realize all examples using name-email pairs are using tuples, but AFAICS it is not explicitly said to be preferred over lists).

Thanks for reading, and thanks in advance for clarifying this issue ^__^

Does not manage connections correctly

As far as I can tell, Emails never closes SMTP connections explicitly. When I send one emails.Message repeatedly, connections are reused, but when I send multiple new messages, connections are leaked.

This can be reproduced by starting a tolerant SMTP server:

$ python -m smtpd -n -c DebuggingServer localhost:1025

and running the following program:

import emails

for i in range(30):
    msg = emails.Message(mail_from='[email protected]', text='hello')
    resp = msg.send(to='[email protected]',
                    smtp={'host': 'localhost', 'port': 1025})
    print(resp.error)

input('Press Enter to quit')

under a stricter limit on open file descriptors:

$ ulimit -n 20

$ python reproduce.py 
None
None
None
None
None
None
None
None
None
None
None
None
None
None
None
None
None
None
None
None
None
[Errno 24] Too many open files: None
[Errno 24] Too many open files: None
[Errno 24] Too many open files: None
[Errno 24] Too many open files: None
[Errno 24] Too many open files: None
[Errno 24] Too many open files: None
[Errno 24] Too many open files: None
[Errno 24] Too many open files: None
[Errno 24] Too many open files: None
Press Enter to quit

At this point we can observe the leaked connections:

$ netstat --inet -p --numeric-ports | grep :1025
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 127.0.0.1:43510         127.0.0.1:1025          ESTABLISHED 22376/python    
tcp        0      0 127.0.0.1:43500         127.0.0.1:1025          ESTABLISHED 22376/python    
tcp        0      0 127.0.0.1:43502         127.0.0.1:1025          ESTABLISHED 22376/python    
tcp        0      0 127.0.0.1:43480         127.0.0.1:1025          TIME_WAIT   -               
tcp        0      0 127.0.0.1:43484         127.0.0.1:1025          TIME_WAIT   -               
tcp        0      0 127.0.0.1:1025          127.0.0.1:43496         ESTABLISHED 22375/python    
tcp        0      0 127.0.0.1:1025          127.0.0.1:43508         ESTABLISHED 22375/python    
tcp        0      0 127.0.0.1:43492         127.0.0.1:1025          ESTABLISHED 22376/python    
tcp        0      0 127.0.0.1:1025          127.0.0.1:43498         ESTABLISHED 22375/python    
tcp        0      0 127.0.0.1:1025          127.0.0.1:43520         ESTABLISHED 22375/python    
[...and so on...]

This can be a problem even in low-throughput cases. I only discovered it because my tests were giving me warnings:

  /home/vasiliy/env/psydiag/lib/python3.5/site-packages/cssutils/prodparser.py:66: ResourceWarning: unclosed <socket.socket fd=13, family=AddressFamily.AF_INET, type=2049, proto=6, laddr=('127.0.0.1', 43616), raddr=('127.0.0.1', 1025)>
    for p in self._prods:

Personally, I would be surprised by implicit connection pooling even if it was done correctly between messages. I prefer the approach of Requests, which only persists connections within an explicit Session.

Lastly, note RFC 5321 § 4.1.1.10:

The sender MUST NOT intentionally close the transmission channel until it sends a QUIT command

Unicode error

Hi!!

Could anyone explain why is this raising a UnicodeEncodeError??
You will see: the text that raises the error, its encoding and the full traceback (if I dosn't make a mistake)
Thanks!!!!

INFO in utils [/Users/garito/TimeFounder/App/0.2/TimeFounder/utils.py:35]:
Your email has been used to ask for an invitation on https://app.timefounder.com.
To register your account click in the link below.
http://localhost:5000/users/signUp?code=ebc601ee-d0a6-11e4-b825-0023dfa2a3b4

If you are not ask for an invitation, please ignore this email

INFO in utils [/Users/garito/TimeFounder/App/0.2/TimeFounder/utils.py:36]:
<type 'unicode'>

127.0.0.1 - - [22/Mar/2015 16:22:08] "GET /users/send_invitation?email=garito%2Bhome%40gmail.com HTTP/1.1" 500 -
Traceback (most recent call last):
File "/Users/garito/TimeFounder/App/0.2/env/lib/python2.7/site-packages/flask/app.py", line 1836, in call
return self.wsgi_app(environ, start_response)
File "/Users/garito/TimeFounder/App/0.2/TimeFounder/init.py", line 82, in call
return self.app(environ, start_response)
File "/Users/garito/TimeFounder/App/0.2/env/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/Users/garito/TimeFounder/App/0.2/env/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception
reraise(exc_type, exc_value, tb)
File "/Users/garito/TimeFounder/App/0.2/env/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "/Users/garito/TimeFounder/App/0.2/env/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/Users/garito/TimeFounder/App/0.2/env/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/Users/garito/TimeFounder/App/0.2/env/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/Users/garito/TimeFounder/App/0.2/env/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
return self.view_functionsrule.endpoint
File "/Users/garito/TimeFounder/App/0.2/env/lib/python2.7/site-packages/flask_principal.py", line 199, in _decorated
rv = f(_args, *_kw)
File "/Users/garito/TimeFounder/App/0.2/Users/init.py", line 166, in send_invitation
send_mail(title, data, recipients)
File "/Users/garito/TimeFounder/App/0.2/TimeFounder/utils.py", line 49, in send_mail
sended[recipientTuple] = msg.send(to=recipientTuple)
File "/Users/garito/TimeFounder/App/0.2/env/lib/python2.7/site-packages/flask_emails/message.py", line 63, in send
return super(Message, self).send(smtp=smtp_options, **kw)
File "/Users/garito/TimeFounder/App/0.2/env/lib/python2.7/site-packages/emails/message.py", line 352, in send
response = smtp.sendmail(**params)
File "/Users/garito/TimeFounder/App/0.2/env/lib/python2.7/site-packages/emails/backend/smtp/backend.py", line 118, in sendmail
msg=to_bytes(msg.as_string(), 'utf-8'),
File "/Users/garito/TimeFounder/App/0.2/env/lib/python2.7/site-packages/emails/message.py", line 423, in as_string
return self.dkim_sign_string(to_bytes(self.build_message(message_cls=message_cls).as_string()))
File "/Users/garito/TimeFounder/App/0.2/env/lib/python2.7/site-packages/emails/utils.py", line 152, in as_string
g.flatten(self, unixfrom=unixfrom)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/email/generator.py", line 83, in flatten
print >> self._fp, ufrom
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/email/generator.py", line 115, in _write
if meth is None:
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/email/generator.py", line 164, in _write_headers
print >> self._fp, Header(
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf3' in position 26: ordinal not in range(128)

Is it dead project?

I noticed the development is pretty stagnant. Is this project support dead or just feature complete but still being actively supported?

Tests fail when running from home

The following two tests:

  • emails/testsuite/message/test_send.py::test_send_letters
  • emails/testsuite/smtp/test_smtp_backend.py::test_smtp_send_with_reconnect

fail on my system, apparently because Microsoft rejects mail from home ISPs like mine (OnLime = Rostelecom):

smtp_servers = {'gmail.com-tls': <emails.testsuite.conftest.SMTPTestParams object at 0x7ff6a8dbccc0>, 'mx.yandex.ru': <emails.testsui...stParams object at 0x7ff6a8dbcc18>, 'outlook.com': <emails.testsuite.conftest.SMTPTestParams object at 0x7ff6a8dbcbe0>}

    def test_send_letters(smtp_servers):
    
        for m, render in get_letters():
            for tag, server in smtp_servers.items():
                server.patch_message(m)
                response = m.send(smtp=server.params, render=render)
                print(server.params)
>               assert response.success or response.status_code in (421, 451)  # gmail not always like test emails
E               assert (False or 550 in (421, 451))
E                +  where False = <emails.backend.SMTPResponse status_code=550 status_text=b"DY-001 (COL004-MC2F34) Unfortunately, messages from 188.32....ically-assigned IP ranges. You can also refer your provider to http://mail.live.com/mail/troubleshooting.aspx#errors.">.success
E                +  and   550 = <emails.backend.SMTPResponse status_code=550 status_text=b"DY-001 (COL004-MC2F34) Unfortunately, messages from 188.32....ically-assigned IP ranges. You can also refer your provider to http://mail.live.com/mail/troubleshooting.aspx#errors.">.status_code

emails/testsuite/message/test_send.py:35: AssertionError
-------------------------------------------------------- Captured stdout call ---------------------------------------------------------
{'timeout': 25, 'tls': True, 'fail_silently': True, 'port': 25, 'host': 'alt1.gmail-smtp-in.l.google.com', 'debug': 1}
{'fail_silently': True, 'timeout': 25, 'port': 25, 'host': 'mx.yandex.ru', 'debug': 1}
{'fail_silently': True, 'timeout': 25, 'host': 'mx1.hotmail.com', 'debug': 1}
-------------------------------------------------------- Captured stderr call ---------------------------------------------------------
[...skip...]
send: 'mail FROM:<[email protected]> size=4203\r\n'
reply: b"550 DY-001 (COL004-MC2F34) Unfortunately, messages from [MY.IP.ADDRESS.HERE] weren't sent. Please contact your Internet service provider. You can tell them that Hotmail does not relay dynamically-assigned IP ranges. You can also refer your provider to http://mail.live.com/mail/troubleshooting.aspx#errors.\r\n"
reply: retcode (550); Msg: b"DY-001 (COL004-MC2F34) Unfortunately, messages from [MY.IP.ADDRESS.HERE] weren't sent. Please contact your Internet service provider. You can tell them that Hotmail does not relay dynamically-assigned IP ranges. You can also refer your provider to http://mail.live.com/mail/troubleshooting.aspx#errors."
send: 'rset\r\n'

The other two SMTP servers are OK.

DKIM issues

Hi, I'm trying to sign my emails with DKIM but some issues or misunderstandings prevent me to do so
This lines are in my flask config file:

DKIM_KEY = open('/dkim/timefounder.com.pem')
DKIM_DOMAIN = 'timefounder.com'
DKIM_SELECTOR = 'mail'

Then I try to use it like:

if current_app.config.get('DKIM_KEY', False):
        msg.dkim(key=current_app.config['DKIM_KEY'], 
                domain=current_app.config['DKIM_DOMAIN'], 
                selector=current_app.config['DKIM_SELECTOR'])

But this error is raised:
Exception on /users/send_invitation [GET]
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1461, in dispatch_request
return self.view_functionsrule.endpoint
File "/usr/local/lib/python2.7/dist-packages/flask_principal.py", line 199, in _decorated
rv = f(_args, *_kw)
File "/app/Users/init.py", line 166, in send_invitation
send_mail(title, data, recipients)
File "/app/TimeFounder/utils.py", line 17, in send_mail
selector=current_app.config['DKIM_SELECTOR'])
File "/usr/local/lib/python2.7/dist-packages/emails/message.py", line 391, in dkim
self._dkim_signer = self.dkim_cls(**kwargs)
TypeError: init() takes at least 4 arguments (3 given)

Giving the fact that I used this from the examples:
message.dkim(key=open('my.key'), domain='mycompany.com', selector='newsletter')

Could someone point me where the error is?

Thanks a lot!

'&#13;' in transformer output html

Symbol '\r' converted to ' ' entity when output_method is default 'xml'.
This is not a bug, html is still valid.
But we should replace '\r\n' to '\n' to decrease file size.

Error When Message Body Is A Zero-length String

Please see this very short and simple gist for an example.

I believe the exception is the result of the _build_html_part method of message.py (currently starting at line 265).

As Python will evaluate a zero-length string as False in a conditional context, the subsequent calls to SafeMIMEText and set_charset are silently skipped and a None is returned.

As the RFC defines an email message body as optional, I believe a zero-length message should be allowed by this library. For my own use-case, I discovered this when setting up some automated reports to be emailed by a CI server as attachments, hence only needing a subject line and the attachments, no message body. Was very simple to workaround by adding a short message, but would like to see this be in closer compliance to the spec.

Slightly off-topic - Great job on this module, it's been extremely simple and enjoyable to work with.

Can not change default output method in transformer

In emails.transformer.HTMLParser default value of output_method parameter can not be changed from inherited class constructors.

When we use default output_method='xml' there are following issue with empty tags:
Input data:
<span></span>123

Expect after loading:
<html><head></head><body><span></span>123</body></html>

Actual after loading:
<html><head><meta content="text/html; charset=utf-8" http-equiv="Content-Type"/></head><body><span/>123</body></html>

And browsers render this like <html><head></head><body><span>123</span></body></html>

Code for proof:

import emails.loader
emails.loader.from_html('<html><head></head><body><span></span>123</body></html>').html

replace charade by chardet

Charade package's README begins with "No Longer Maintained" and suggests to use chardet instead.
So the charade calls should be replaced by chardet

Multiple recipients on 'to='

Hello Mr. Lavrinenko,

I recently found your code on GitHub and am really enjoying the work you have done on creating the python library for emails!

But I was wondering how to add multiple recipients on the

to=

line.

Thank You for all your hard work!

Unicode subject headers encoding inserting new line into headers causing lib to error out

Hello, I am working for Points.com and we are using your lib to send out emails. We are implementing internationalization and ran into issue with the library.

Steps:
Use non-ascii chars in the subject of the email. Use 24+ chars for Russian (or 30 char for German) languages in the subject
Create email message and call message.send()

Expected:
email sent successfully

Actual:
Getting the following exception:

emails.utils.BadHeaderError: Header values can't contain newlines (got u'=?utf-8?b?0LbQttC20LbQttC20LbQttC20LbQttC20LbQttC20LbQttC20LbQttC20LY=?=\n =?utf-8?b?0LbQttC20LbQttC20LbQttC20LbQttC20LbQttC20LbQttC20LbQttC20LY=?=\n =?utf-8?b?0LbQttC20LbQttC20LbQttC20LbQttC20LbQttC20LbQttC20LbQtg==?=' for header u'Subject')

If I use under 24 Russian chars in the subject email is sent successfully. So the issue depends on number of unicode characters in the subject line. It looks like pyhton's standard module headers.py inserts newline during encoding which is bizarre.

I propose the fix to simply strip new line chars after encoding, instead of rejecting the message with BadHeaderError or we need to figure out why headers.py inserting newline char and find a way to prevent it.

Let me know about your thoughts on this issue. We will fix the issue once we agree on the solution.

Attached is a little test script that I wrote that shows how to reproduce an issue:

Python 2.7 on Ubuntu 12.04

# -*- coding: utf-8 -*-

import emails

HTML = '<html>Test Test Test</html>'
SMTP = {
        'host': 'somemailhost.domain.com',
        'port': 25,
        'ssl': False
    }

if __name__ == '__main__':

    message = emails.html(subject=u'жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж',
                          html=HTML,
                          mail_from='[email protected]')
    response = message.send(to='[email protected]', smtp=SMTP)
    print(response)

Sending the same mail twice

Hi,

I am trying to send a mail with a zip file attached. When it is a PDF or Text file everything is working as expected, but when i send a zip file it sends the same mail twice. This is how i send a mail with a zip file attached:

message = emails.html(html="<p>Hi<br>Attached is the Monthly Availability and Latency report.", subject="Test Subject2018", mail_from=('Sender','[email protected]'))

message.attach(content_disposition="inline",data=open('E:\Availability\Test.zip', 'rb'), filename='Test.zip')

r = message.send(to='[email protected]', smtp={'host': 'mail.mnet-online.de', 'timeout': 5})

Support lazy django templates rendering (DjangoMessage)

Now we have to make explicit django template rendering:

    from django.template.loader import get_template
    DjangoMessage(html=get_template(template_name).render({'a': 42}, ...)

Proposed way is to support lazy rendering:

    m = DjangoMessage(html=get_template(template_name)
    m.render({'a': 42}, ...)

Lazy rendering and transform.save() issue

Greetings. Seems like creating message from template for later rendering and applying transformers doesn't work one with another? Like I see all other message methods, for example dkim signature works lazy, so I can do something like this:

msg = Message(subject=Template(), html=Template())
msg.dkim(**dkim_options)

and later msg.send(to, render=context)
But transformer.save() modifies not rendered template, but template.template_text before rendering (for example this would not work properly with extending template from base).
I should not use template feature in this case, or what's the proper way to do this?
Also maybe there should be method of Message to implement, that can modify message after template rendering? Thanks for your help and ideas...
Really cool lib, by the way. Thanks

Feature: skip external image loading based on url content

emails loader does not load external images if img tag has attribute data-email="ignore".
So human (designer) can make a decision to load image or not on html design phase.

But I need more control on image loading.
For example, I want loader never loads Google Analytics pixel-counter or always leave url for images already published on company's external website.

Propose is to make a callback than checks img element and returns True/False if image should be loaded or not.

Got UnicodeEncodeError: on python 3.5

Here is the code:

        from emails import Message
        message = Message(
            subject='test',
            html='<html>Привет</html>', mail_from="[email protected]"
        )

        message.send(to='[email protected]')

and the error:

  File "manage.py", line 121, in created_eqs_notify
    message.send(to='[email protected]')
  File "/home/kalombo/.virtualenvs/dev3/lib/python3.5/site-packages/emails/message.py", line 404, in send
    return smtp.sendmail(**params)
  File "/home/kalombo/.virtualenvs/dev3/lib/python3.5/site-packages/emails/backend/smtp/backend.py", line 119, in sendmail
    rcpt_options=rcpt_options)
  File "/home/kalombo/.virtualenvs/dev3/lib/python3.5/site-packages/emails/backend/smtp/backend.py", line 80, in wrapper
    return func(*args, **kwargs)
  File "/home/kalombo/.virtualenvs/dev3/lib/python3.5/site-packages/emails/backend/smtp/backend.py", line 103, in _send
    return client.sendmail(**kwargs)
  File "/home/kalombo/.virtualenvs/dev3/lib/python3.5/site-packages/emails/backend/smtp/client.py", line 105, in sendmail
    (code, resp) = self.data(msg)
  File "/usr/lib/python3.5/smtplib.py", line 562, in data
    msg = _fix_eols(msg).encode('ascii')
UnicodeEncodeError: 'ascii' codec can't encode characters in position 679-684: ordinal not in range(128)

Import jinja template from external file

Hi, nice library!

Is it possible to import a template from an external file (for example template.html)? I've adapted the example code in the docs, but am getting a TypeError - see below.

If this is possible, I'm happy to send a pull request to extend the docs examples.

sendemail.py

import emails
from emails.template import JinjaTemplate as T

message = emails.html(
     subject=T('Payment Receipt No.{{ billno }}'),
     html=T(open('template.html')),
     mail_from=('ABC', '[email protected]')
     )

r = message.send(...)

This gives:

$ python sendemail.py
Traceback (most recent call last):
... 
TypeError: Can't compile non template nodes

Is Python 3.5 supported?

I’d like to use Emails under Python 3.5, but I notice that, unlike 3.4 and 3.6, it’s missing from your Tox config, which explicitly says “all supported python versions”, as well as from Travis config and trove classifiers (though 3.6 is missing from the latter, too).

Are there any known problems with using Emails under Python 3.5?

message.py, render takes 1 arg but 2 given

Hello, we found another issue with the library and this one is critical (lib does not work at all).

File "/.../.../.../local/lib/python2.7/site-packages/emails/message.py", line 340, in send
    self.render(render)
TypeError: render() takes exactly 1 argument (2 given)

Issue is right here, ***kwargs is not technically counted as an arg.

    def render(self, **kwargs):
        self.render_data = kwargs

By the way, I don't see any tests with the source, do you keep the tests separately? I don't mind contributing and helping you to fix an issue, but I would like to work with the source that is covered by tests to know that I am not breaking anything else.

Using this library with SMTP servers that require authentication

Hi, is this possible to use this library with SMTP servers that require authentication?
I've tried passing "username" and "password" keys to the smtp dictionary but I get an "unexpected keyword argument" exception.

I've looked into it and it looks like SMTPClientWithResponse.init() should also wrap smtplib's login() method somehow.

Thanks :)

m = emails.Message(text="text",  subject="subject",  mail_from=("CI", "[email protected]"))
response = m.send(to='[email protected]',
                               smtp={"host":"smtp.gmail.com", "port": 465, "ssl": True, "username": "user",  
                               "password": "pass"})

Python 3.7 deprecation warning

There are some deprecation warnings when running with py3.7.

.../python3.7/site-packages/emails-0.5.15-py3.7.egg/emails/compat/orderedset.py:5: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  from collections import MutableSet

.../python3.7/site-packages/emails-0.5.15-py3.7.egg/emails/compat/__init__.py:121: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  from collections import OrderedDict, Callable

Maybe it's time to remove some old versions (e.g. 2.6) too?

Adding documentation: handcrafted .rst files vs. Sphinx autodoc?

I noticed documentation is listed as the first todo on the docs homepage.

Is there any preference, or considerations, for what should be covered or how this should be added?

From a user point-of-view, I would have found full documentation on the available params for the main functions useful: emails.Message, emails.html, emails.attach and emails.send for example.

To document these functions, it would seem the options are adding to the existing using standalone .rst files or perhaps using Sphinx autodoc?

Happy to begin writing, but keen to make sure it fits in with the desired way of doing this...

PNG inline attachment doesn't work

Attaching png image as inline does appear in dispatched mail.
Code sample -

emsg = emails.Message(html=html, text=text,
                       subject="Welcome", mail_from=("Tester", settings.EMAIL_DEFAULT_SENDER))
emsg.attach( 
        filename="logo.png", 
        content_disposition="inline", 
        data=open(os.path.join(settings.STATIC_DIR, "images/logo.png")))
connection.sendmail(from_addr=settings.EMAIL_DEFAULT_SENDER, to_addrs=['[email protected]'], msg=emsg)

Sent this content through Amazon SES. Here is partial content from result mail -

--===============0125573738==
Content-Type: image/png; name="logo.png"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: inline; filename="logo.png"
Content-ID: <logo.png>

iVBORwo=

--===============0125573738==--

Silent fail if port param is Unicode string

In Python 2.7.13 on Windows 7., running v0.5.13, the program:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import unicode_literals
import emails

SMTP_USER = '[email protected]'
SMTP_PASS = 'abracadabera'
SMTP_HOST = 'smtp.gmail.com'
SMTP_PORT = '587'
SMTP_FROM = '[email protected]'
SMTP_TO = '[email protected]'

m = emails.Message(text='body', subject='subject', mail_from=SMTP_FROM)
smtp={'debug': 1, 'host':SMTP_HOST, 'port': SMTP_PORT, 'tls': True, 'user': SMTP_USER, 'password': SMTP_PASS}
response = m.send(to=SMTP_TO, smtp=smtp)
print(response)

produces no logs, but this result:

<emails.backend.SMTPResponse status_code=None status_text=None>

If I change

SMTP_PORT = '587'

to

SMTP_PORT = 587

or

SMTP_PORT = str('587')

it works fine.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.