Hacker News new | past | comments | ask | show | jobs | submit login
Envelopes - Python email for humans (tomekwojcik.github.io)
119 points by RobSpectre on Aug 7, 2013 | hide | past | favorite | 34 comments



If this works as well as Python's requests library, then you are my hero. I hate dealing with email in Python, because the standard library interfaces to email are horrible.

I have a have a project that could use this now, so I will give it a shot. I will report back with my findings.


Anyone who calls their project "Library_Name for Humans" has big shoes to fill. Looking at the examples, it appears to be exactly that.


perhaps there should be an official group for 'for humans' projects?


I'm aiming at Requests' robustness, but it's still a long way to go for Envelopes. Good news is - it works and sends e-mails :).

If you find any issues please report them at GitHub. Thanks and have fun.


From an API standpoint:

(1) I feel like sending emails isn't a task that's going to be repeated endlessly across a codebase, so is it really necessary to save three characters by truncating "from_address" to "from_addr"? You lose clarity for very little gain.

(2) If truncating the above was so important, why is it "text_body" instead of just plain "body"? In this case, you'd lose almost no clarity.

I prefer APIs to not have unnecessarily abbreviated words—especially when, realistically, I'm going to type them once per file.

(Sorry, pet peeve.)


The API is still young and I'm perfectly aware it could use some love (especially that I wrote the first Envelopes class at 3AM while trying to simplify my workflow).

I've been considering renaming "from_addr" and "to_addr" to "from" and "to" but this would cause conflicts with Python's keywords. I'm, however, all over renaming them to "from_address" and "to_address". As far as "cc_addrs" and "bcc_addrs" - I think I'll use full "address" there, too (for the sake of consistency).

As for "text_body" and "html_body" - I'd like to leave those as they are. Depending on the case I may use one of them, both of them or neither of them.

Thanks for your feedback, it's much appreciated :).


It is called text_body because there is also an html_body.

http://tomekwojcik.github.io/envelopes/api/envelope.html


So if you set both, will it auto-magically do multipart/mime/alt? That is pretty nice.


Ah good call. Maybe it's just my very maleable Javascript side talking, but if I were making this API in Javascript I'd probably have a "body" and do a super simple check if the first character is a "<", which will solve the 99.999% case for HTML vs. text emails.


But then your emails can't have HTML and a plaintext backup.


Ah I should have clarified that "body" would be a shorthand of sorts. I'd still have an "html" and "text" alternative to satisfy the case where you want to set both, and in that case "text" and "html" are very meaningful. But the "body" makes the simple case, and the examples extremely clean too.


Agreed about abbreviations.

To distinguish "text_body" and "html_body", what about simply "text" and "html"? That's what we use internally.

Also, how does one send To: multiple addresses with this library? I think it'd be good if to_address could be a list (or their was a separate to_addresses, which could be a list).

I like it how cc_addrs / bcc_addrs can be a list already, of either addresses or (email, name) tuples. Why not do the same thing from from_address and to_addresses, and get rid of from_name and to_name?


Honestly I didn't even see the "cc_addrs" and "bcc_addrs". Those are horrible. Now you have complex abbreviations that are pluralized! I completely agree.

And while we're making them accept lists or tuples, change their names to: "to", "from", "cc" and "bcc". Very clear and still a tiny amount of characters.


that's what I was thinking of. Accepting dicts or tuples would be ok. Even just using [ "Name <email address>", "name <email address>"] would be more human.


Note that, for CC and BCC addresses, there's a number of accepted formats. Consult docs for more info: http://tomekwojcik.github.io/envelopes/api/envelope.html


I'm talking about to field also.


I feel I should mention Mailer

https://pypi.python.org/pypi/mailer

I think everyone who has ever used the python standard library email modules has had the thought "Well, if I just made a small wrapper around this... it wouldn't be so bad"

And just about everyone who thought that did it.


Looks pretty good. Being a Flask user, happy to see the flask example as well. Would definitely try and use it in side projects of mine. You open to any forks and/or pull requests ?


As a Flask user, you might want to check out Flask-Mail http://pythonhosted.org/flask-mail/


Thx. I know of flask-mail already. Just wanted to see how different would the "envelopes" be .


If they can add IMAP, POP, possibly Exchange, and good email parsing (it's truly a pain in the ass to do yourself) this will be a killer library.


I'd also be interested in an email parsing library for Python. Last time I used Twisted to read email the parser was completely worthless and could not be fixed other than by rewriting it from scratch.


Nice wrapper, though it took me a while to get it to work. Tried with Google SMTP, but ended up throwing Sendgrid on a heroku app and hit that api.

Wondering if a debug mode would be helpful for the initial set up. See what requests are being sent/received to see what the possible errors are.


Debug mode is a nice catch. Thanks.

As far as GMail SMTP goes, I've been using Envelopes over GMail SMTP for about a week with great success. The first example in the docs shows just that. Also, I have customized SMTP subclasses for GMail, SendGrid and local Mailcatcher in the pipeline. Using one of them, you'll only have to provide your creds to send e-mails.


What is the advantage of having an Envelope class? Why not just have a send function?


Maybe so you can more deliberately build different parts of the email in different parts of the code without having to create your own set of variables for that.


I find it a little weird that you would create the email in one part of the code and then send it somewhere else though. The only advantage I can think off is something like falling back to another connection if the primary one fails. But it's strange to support reuse of messages while at the same time not being able to reuse a connection.

Why not have a set of classes for flexibility and simple helper functions for the most common cases? Requests is so great to use because the API matches the expectations of its users (how do I make a GET request? oh, use the get function...) and I think for email a single send function does what people want most of the time.

send( 'smtp.googlemail.com', login='from@example.com', password='password', from_address=u'from@example.com', from_name=u'From Example', to_address=u'to@example.com', to_name=u'To Example', subject=u'Envelopes demo', text=u"I'm a helicopter!" )

connection = Connection( 'smtp.googlemail.com', login='from@example.com', password='password' )

message = Envelope( from_address=u'from@example.com', from_name=u'From Example', to_address=u'to@example.com', to_name=u'To Example', subject=u'Envelopes demo', text=u"I'm a helicopter!" )

message.add_attachment('/Users/bilbo/Pictures/helicopter.jpg')

connection.send(message)


envelopes.conn.SMTP is a wrapper for smtplib.SMTP that supports Envelope objects and is reusable. Envelope.send() is just a shorthand you can use if you don't care about reusing connections.

For requests it's simpler to support top-level functions, since in general HTTP request is self-contained. Envelope (or email.mime.MIMEMessage) object isn't enough to send an e-mail - you need to know the SMTP host, port, creds and set up the connection. While it's certainly possible to write envelopes.send() function that'd internally create an Envelope object and send it (all based on the args the function gets) I don't think it's that crucial.


Envelopes looks very good for sending emails and for reading emails there is another cool library - Imbox https://github.com/martinrusev/imbox


We use boto to send email via Amazon's Simple Email Service and it is fairly simple. SES allows you to send up to 2000 emails per day for free.


Would you be willing to collaborate a SES mailer wrapper for this similar project? https://github.com/lucuma/MailShake


Seems really nice with a first glance. Are you considering any Django support in the future?


Django's Email API is already pretty solid, see the EmailMessage[0] class. Attachments and multiple MIME types are handled for sending text & html versions of the email body.

However, given that Django is just Python there's nothing precluding you from using the library as a drop-in replacement.

[0] https://docs.djangoproject.com/en/dev/topics/email/#emailmes...


I don't generally do Django, but I don't think it should be a problem. Just a word of warning - if you're going to use a global per-app SMTP connection remember to wrap it in connstack. The Flask example shows this and it shouldn't be hard to do the same in Django.




Consider applying for YC's W25 batch! Applications are open till Nov 12.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: