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.
(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.
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 :).
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.
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.
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.
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"
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 ?
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.
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.
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.
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.
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.
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.
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.