Re:Show HN: email - Send emails easily in Go
by curveship on Tuesday January 07, 2014 @05:20PM
(#7020413)
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.
Re:Show HN: email - Send emails easily in Go
by jwcrux on Tuesday January 07, 2014 @06:57PM
(#7020856)
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!
Re:Show HN: email - Send emails easily in Go
by jwcrux on Tuesday January 07, 2014 @06:39PM
(#7020792)
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.
Re:Show HN: email - Send emails easily in Go
by elithrar on Tuesday January 07, 2014 @06:32PM
(#7020765)
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...)
Re:Show HN: email - Send emails easily in Go
by jwcrux on Tuesday January 07, 2014 @11:26PM
(#7021684)
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]
Re:Show HN: email - Send emails easily in Go
by mratzloff on Tuesday January 07, 2014 @04:28PM
(#7020083)
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.
Re:Show HN: email - Send emails easily in Go
by yixizhang on Tuesday January 07, 2014 @07:13PM
(#7020919)
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.
Re:Show HN: email - Send emails easily in Go
by jwcrux on Tuesday January 07, 2014 @02:30PM
(#7019300)
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.
Re:Show HN: email - Send emails easily in Go
by scott_s on Tuesday January 07, 2014 @07:20PM
(#7020949)
Stuart Feldman, from "The Art of Unix Programming", on why makefiles must use tabs:
"Why the tab in column 1? Yacc was new, Lex was brand new. I hadn't tried either, so I figured this would be a good excuse to learn. After getting myself snarled up with my first stab at Lex, I just did something simple with the pattern newline-tab. It worked, it stayed. And then a few weeks later I had a user population of about a dozen, most of them friends, and I didn't want to screw up my embedded base. The rest, sadly, is history."
Re:Show HN: email - Send emails easily in Go
by mseepgood on Tuesday January 07, 2014 @05:41PM
(#7020514)
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.
Re:Show HN: email - Send emails easily in Go
by ihsw on Tuesday January 07, 2014 @02:30PM
(#7019296)
In actuality it would be `email.NewEmail()` -- the lack of namespace specificity is due to the code examples already being part of the package. The issue with a simple `New()` 'constructor' is that there is ambiguity as to what struct it's creating.
- 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.
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!
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
and then, if a value hasn't been set for it, use a default value for Headers in the send method.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!
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...)
"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
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.
That is pretty badass.
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
[2] https://sites.google.com/site/gopatterns/object-oriented/con...
"Why the tab in column 1? Yacc was new, Lex was brand new. I hadn't tried either, so I figured this would be a good excuse to learn. After getting myself snarled up with my first stab at Lex, I just did something simple with the pattern newline-tab. It worked, it stayed. And then a few weeks later I had a user population of about a dozen, most of them friends, and I didn't want to screw up my embedded base. The rest, sadly, is history."
http://golang.org/doc/effective_go.html#names
To be fair, you could write:
e = &email.Email{ [fields and values] }
The only thing NewEmail does is give you a pointer to an Email.