

Show HN: email - Send emails easily in Go - jwcrux
https://github.com/jordan-wright/email#email

======
curveship
I'm a novice at Go, but I've written several email libraries in other
languages. Two lessons from that experience that I thought I'd pass on:

\- I've found it a more flexible architecture to separate the send
functionality off from your email object itself and into its own service
class. So instead of doing email.Send(), you do emailService.Send(email). The
content of an email, and how to send that content, are separate
responsibilities. Separating the two also allows for alternate implementations
of the Send functionality: one (like here) that does a synchronous SMTP
transfer, one that might drop the message into an internal queue so that
client code doesn't need to wait for the (potentially fairly slow) SMTP
transfer, one that simply appends to a local file for debugging, etc. (These
are all examples from real apps.)

\- Have you considered making required properties (to, from, subject)
properties of the constructor? Doing so makes guaranteeing that they're set a
compile-time check rather than a runtime check, which can make a library more
robust and suss out bugs earlier.

~~~
jwcrux
Thanks for the suggestions!

1) I worked to create the package such that other sending services can easily
be used to send the email. By calling the .Bytes() function, you will get a
slice of bytes which is the raw email representation that's meant to be sent
across the wire. I only included the Send() function as a helper.

2) I'm actually not sure if there's a way to do this in Go.. I suppose I could
have made the NewEmail() function take arguments for required items - and I
did think about doing this- but what arguments? In what order? Using previous
libraries, I've always had to go look up the docs every time I use them
because I forget what order the to and from are supposed to be in.

Currently, only runtime checks are performed to make sure there is at least
one from and to addresses given.

Thanks for the suggestions - I really appreciate it!

------
dradtke
Looks interesting. A couple suggestions:

1\. People have already suggested this, but it would make more sense to make
users call email.New() rather than email.NewEmail().

2\. Alternatively, since the user will be populating a bunch of values anyway,
it might make more sense to tell users to create a message like

    
    
        e := &email.Email{
            From: "Jordan Wright <test@gmail.com>",
            To: []string{"test@example.com"},
            ...
        }
    

and then, if a value hasn't been set for it, use a default value for Headers
in the send method.

~~~
jwcrux
With regards to 1, it seems like I'm stuck between a rock and a hard place. I
originally made the package in accordance to the docs I read which stated that
if you are exporting more than one type, use NewType(). Now that so many
people are using the package, I'd hate to make changes that would break it
unless necessary.

However, with that being said, 2 might solve that issue. I'll add an example
this evening showing how to also create an email in one pass using an example
similar to yours.

Thanks for the suggestions!

------
hendler
Here's a Go smtpd. [https://github.com/flashmob/go-
guerrilla](https://github.com/flashmob/go-guerrilla)

------
nodesocket
Wish somebody would made a go client for Mandrill (by MailChimp).
[https://mandrillapp.com/docs/integrations.html](https://mandrillapp.com/docs/integrations.html)

~~~
jwcrux
[https://github.com/mattbaird/gochimp](https://github.com/mattbaird/gochimp)

~~~
elithrar
Beat me to it.

I've been using gochimp to send emails with Mandrill templates (using
MergeVars) with much success. I send them async when a user creates their post
and log the details. Also means I don't have to either a) run a mail server
locally or b) store a user/pass in plaintext (like so many tutorials like to
do...)

------
bnb
You could even call it... GMail.

------
zavi
Using plain text Gmail password looks like a red flag.

    
    
      e.Send("smtp.gmail.com:587", 
              smtp.PlainAuth("", 
                             "test@gmail.com", 
                             "password123", 
                             "smtp.gmail.com"))

~~~
jwcrux
I am wrapping SendMail..

"SendMail connects to the server at addr, switches to TLS if possible,
authenticates with the optional mechanism a if possible, and then sends an
email from address from, to addresses to, with message msg"[1]

[1][http://golang.org/pkg/net/smtp/#SendMail](http://golang.org/pkg/net/smtp/#SendMail)

------
mratzloff
This looks great! It will definitely make my life easier. Thanks for sharing.

~~~
Edmond
that homepage of yours is something special :)

~~~
mratzloff
And all valid HTML5. :-)

I confess that I'm a bit nostalgic for a time not that long ago when people
made their own websites about their interests instead of updating their
Facebook profile with pointless status messages.

------
yixizhang
The easiest way and properly the right way to send email is in plain text. I
would be happier if the package can add a parser to read all meta data from
text, in the way of HTTP header processing.

------
tshadwell
Interesting choice of NewEmail() over the more idiomatic email.New().

~~~
jwcrux
Good point - when developing the package, I was referencing these [1][2]
documents which showed the use of NewObject() instead of New(). I figured
since I provide more than one possible struct (both Email and Attachment), the
use of NewEmail would provide consistency.

However, now that you mention it, I suppose it wouldn't have hurt, and the
meaning would have been fairly clear. Oh well - live and learn, at this point,
I'm doing my best not to break backwards compatibility if I don't have to.

Thanks for the heads up!

[1]
[http://golang.org/doc/effective_go.html#composite_literals](http://golang.org/doc/effective_go.html#composite_literals)

[2] [https://sites.google.com/site/gopatterns/object-
oriented/con...](https://sites.google.com/site/gopatterns/object-
oriented/constructors)

~~~
DrJokepu
If your package exports a single type only, New is more appropriate, if it
exports multiple types, you should use NewObject:

[http://golang.org/doc/effective_go.html#names](http://golang.org/doc/effective_go.html#names)

~~~
mseepgood
Many packages have a dominant type and a couple of satellite types. If the
package name is the same as or similar to the name of the dominant type, 'New'
can be appropriate as well.

~~~
DrJokepu
Right. As long it’s super obvious which type New creates, it’s perfectly fine.

