lavr / python-emails Goto Github PK
View Code? Open in Web Editor NEWModern python library for emails
Home Page: http://python-emails.readthedocs.org
License: Other
Modern python library for emails
Home Page: http://python-emails.readthedocs.org
License: Other
def recipients(self):
"""
Returns a list of all recipients of the email (includes direct
addressees as well as Cc and Bcc entries).
"""
return self.to + self.cc + self.bcc
I would have fixed it myself but I don't know what self._recipients
does.
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)
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.
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==--
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.
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.
Would love to see a more consequent use of properties, e.g. get_cc should be property cc.
Transformer fails on RFC 2397 data url scheme.
One should write test with embedded image, paste traceback here and discuss how to fix.
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.
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)
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.
Allow for Cc on email message
Actually the method send of DjangoMessage doesn't return the result of sending. So it is impossible to exploit the status code of the result.
It would be nice to do the same way as Django email module does.
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"})
This html is broken at least in Chrome:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title/>
</head>
<body>
...
The problem is in empty <title/>
tag, I guess.
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})
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
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 ^__^
ZIP import fails on some files.
Example zip file content:
__MACOSX/
__MACOSX/._for-kglad.html
for-kglad.html
zip loader chooses invalid file __MACOSX/._for-kglad.html
SMTPBackend.send may raise socket.timeout on connection phase or during smtp session.
Let's be more specific about it.
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
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?
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
Getting error when I add CC while sending emails.
TypeError: send() got an unexpected keyword argument 'cc'
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!
There are two known errors installing emails on python 3.3:
pip-3.3 install lxml
failed.apt-get install zlib1g-dev libxml2-dev libxslt1-dev python3.3-dev
pip-3.3 install chardet
failed.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)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.
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
Charade package's README begins with "No Longer Maintained" and suggests to use chardet instead.
So the charade calls should be replaced by chardet
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.
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
How can i send email from gmail using this module ?
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.
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!
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
In case any other fellow programmer wants to save 10 mins to integrate python-emails
with Amazon SES, I've posted a little Gist here:
https://gist.github.com/flevour/c145c99e5b049bf11877ea4985cbb0fa
The benefit of using SES via API vs via SMTP is you can re-use the same credential pair you use to access all other APIs whereas SMTP requires a different pair to be generated.
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 =================================================
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)
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>
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}, ...)
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...
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?
I noticed the development is pretty stagnant. Is this project support dead or just feature complete but still being actively supported?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.