go-gomail / gomail Goto Github PK
View Code? Open in Web Editor NEWThe best way to send emails in Go.
License: MIT License
The best way to send emails in Go.
License: MIT License
I made a quick review of your code and I think you open close a connection for each Send
(https://github.com/go-gomail/gomail/blob/master/send.go#L22).
I want to implement a job to send emails from a queue in bulk, but reusing the connection to be as more efficient as possible.
I miss something from your API?
Thanks!
~/go/src# go get gopkg.in/gomail.v1
Segmentation fault (core dumped)
Please help me out
The example in FAQ is incorrect:
d := gomail.NewPlainDialer("smtp.example.com", "user", "123456", 587)
Should be:
d := gomail.NewPlainDialer("smtp.example.com", 587, "user", "123456")
In some conditions, BASE64 encoding of headers is required, for example when a " character is present in a To: or From: address. However, setting BASE64 as the encoding will also cause the body to be BASE64 encoded, which will lead many spam filters to flag the message as spam. This is true at least for SpamSieve, but possibly many others.
I have 50 worker goroutines that start with a channel passed in. Then, the process forever loops reading 100 database records at a time and sleeping for 10 seconds in between database calls. As it loops through the 100 email records to send, it passes each record through the channel to one of the 50 workers, who then sends the email. The problem is, after it goes through about 1000 emails, I start getting errors like this:
gomail: could not send email 1: read tcp 10.2.30.25:56708->216.146.40.110:25: read: connection reset by peer
I have to send out about 50k emails per day. What do you recommend? Here's the main code that processes the email queue and passes each record to the worker through the channel:
func main() {
MaxWorkers := 50
println("Creating: " + strconv.Itoa(MaxWorkers) + " workers..")
batchChannel := make(chan EmailQueue.EmailQueueObj)
for i := 0; i < MaxWorkers; i++ {
go startWorker(batchChannel)
}
for {
println("Getting queue..")
data, _ := EmailQueue.GetQueue() //returns 100 database records
println("Reading through " + strconv.Itoa(len(data)) + " records..")
for _, element := range data {
batchChannel <- element
}
time.Sleep(10 * time.Second)
}
}
func startWorker(channel chan EmailQueue.EmailQueueObj) {
var s gomail.SendCloser
var err error
open := false
for obj := range channel {
if !open {
s, err = dialer.Dial()
if err != nil {
fmt.Println(err.Error())
return
} else {
sendEmail(obj, &s)
}
} else {
sendEmail(obj, &s)
}
open = true
}
s.Close()
}
func sendEmail(obj EmailQueue.EmailQueueObj, s *gomail.SendCloser) {
m := gomail.NewMessage()
m.SetHeader("From", "[email protected]")
m.SetHeader("To", obj.Recipient)
m.SetHeader("Subject", obj.Subject.String)
m.SetBody("text/html", obj.HTML.String)
// Send the email
response := ""
status := ""
if err := gomail.Send(*s, m); err != nil {
response = err.Error()
status = "error"
} else {
response = "Email sent"
status = "sent"
}
m.Reset()
return
}
Hi .
I am trying to relay on a server with no authentication .
using a telnet client , I can simply :
I tried to create an Auth with Start function that returns immediately , with empty return value , or "MAIL FROM:" , but I guess no matter what I do , smtp package will go through :
code, msg64, err := c.cmd(0, "AUTH %s %s", mech, resp64)
that the server will decline .
Do you have an idea for doing anonymous connection/ESMTP AUTH .
my best help so far was http://www.fehcom.de/qmail/smtpauth.html
Thanks .
Hello,
when embedding more than one files (1.png, 2.png, 3.png), letter contains only last file (3.png).
It would be useful to have the parts exposed so we can test the body of an email (eg. is the correct activation link present in the email?).
What do you think?
Embed should allow setting filename and cid separately
Hi!
This library is very helpful.
However, I encountered an inconsistent behaviour which I believe is a bug.
When a file given as an argument to Message.Embed(...)
is missing on the filesystem,
there's no error returned (this method returns nothing).
Later, when calling Send(sender, message)
,
error is returned, but the email is sent (without embedded data of course).
This is confusing - I'd rather expect that when there's an error, an email would not be sent. When it works this way, I cannot really differentiate between such error and other error stopping message from being sent.
For example, if the character "," is present in a header field, it must be encoded because it is the address separator character in the address-list (RFC 2822) production rule.
Hello I am using your gomail to login to Gmail to send activation emails for my website. However I got this in my email saying:
"Sign-in attempt prevented
Hi xxxxxx,
Someone just tried to sign in to your Google Account [email protected] from an app that doesn't meet modern security standards.
"We strongly recommend that you use a secure app, like Gmail, to access your account. All apps made by Google meet these security standards. Using a less secure app, on the other hand, could leave your account vulnerable."
How do I make my signing attempt more secure? I used the standard
d := gomail.NewPlainDialer("smtp.gmail.com", 587, "[email protected]", secretpass)
to send the gmail. Any tips?
Since go get does not currently support go15vendorexperiment, what is the right way to get this library? And also to import it into the project?
Inside project/src/vendor do a
git clone --depth=1 https://github.com/go-gomail/gomail github.com/go-gomail/gomail
then in code
import "github.com/go-gomail/gomail"
It seems to work for me, but just wanted to make sure.
I have the feeling that those signatures should have io.Reader instead of *File
func OpenFile(filename string) (*File, error)
func (msg *Message) Attach(f ...*File)
func (msg *Message) Embed(image ...*File)
And using ioutil.ReadFile
(inside CreateFile()
) will dump whole file contents right into memory...Which is not very good for performance and in general.
I wonder if it's possible to send multiple emails over one SMTP connection and if it would improve the performance? I just tested your library, it's very smooth to use but it takes about 8 seconds to send 10 mails with the same mailer object.
Hi,
As you state in the comments, e-mails are sent with "localhost" as the default hostname during the SMTP helo stage.
It causes some trouble as many anti-spam solution would badly penalize any e-mail sent by a machine presenting itself as "localhost".
Please update the function so that it takes the hostname as an argument.
func NewDialer(host string, port int, username, password string) *Dialer {
return &Dialer{
Host: host,
Port: port,
Username: username,
Password: password,
SSL: port == 465,
LocalName: "test.domain",
}
}
This error seems to be happening on go 1.4.1. It works on go 1.3.3. Is there an incompatibility with go 1.4.1?
I am looking at message.go and AddAlternativeWriter
currently replaces (does not add to) the message parts. Shouldn't this do append()
instead?
Is there a way to receive a messageId/responseCode returned by SMTP server? Like amazon-ses returns SMTP responses as here : http://docs.aws.amazon.com/ses/latest/DeveloperGuide/smtp-response-codes.html
Hello,
I would like to send emails with embedded files from URLs.
SetCopyFunc
only has access to io.Writer.
How would one replace os.Open
with i.e http.Get
?
It seems like it might be a good idea to make Message an interface in gomail rather than a concrete struct. This would allow users of the library to use the sending functionality separately from the message creation functionality.
I'm was looking at switching over my rss mailer (https://github.com/hobeone/rss2go) to use gomail and ran into this. I could rework my mailer to use gomail.Message directly but I thought that maybe this pointed out a way to make gomail better.
subj. ;)
`
message.SetBody("text/plain", "Hello pj")
message.AddAlternative("text/html", "Hello html <b>pj</b>")
`
This produces:
`
--908b4cfdd408aaeb4ad5a5525eed978aa6361f8e322bf69397de36fa21d6
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Hello pj
--908b4cfdd408aaeb4ad5a5525eed978aa6361f8e322bf69397de36fa21d6
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Hello html pj
--908b4cfdd408aaeb4ad5a5525eed978aa6361f8e322bf69397de36fa21d6--
`
Hotmail shows the html version.
Gmail shows the html version.
Hi,
When running the command 'go get gopkg.in/gomail.v1' the following error was produced:
gopkg.in/alexcesaro/quotedprintable.v2
../../src/gopkg.in/alexcesaro/quotedprintable.v2/header.go:73: undefined: sync.Pool
https://github.com/alexcesaro/quotedprintable/blob/v2/header.go (line 73).
I am running go 1.4.2 in a Windows environment.
With the current API, you can call SetAddressHeader once, which will pass the input through FormatAddress and set the header, or you can format multiple addresses with FormatAddress and then set the address header with a slice containing the formatted addresses.
However, the second method does not work because FormatAddress may encoding an address as needed. Then, SetHeader will encode the address again, yielding a twice-encoded final value.
Hi there,
I am trying to use following sender variable in multiple goroutine to send emails, But it does not work. (I pass same initialized sender variable in function which gets executed in goroutines pool)
It returns gomail: could not send email 1: EOF error and does not proceed
mailer := gomail.NewPlainDialer(smtpServer, smtpPort, smtpUser, smtpPassword)
sender, err := mailer.Dial()
if err != nil {
log.Println("Mailer Could not be instantiated. Error: ", err)
}
I already tried DialAndSend() in goroutines pool and it works. But I do not want to connect to server for each email as it gives multiple login attempts error from gmail server after sending more than 50 emails at same time.
Any hep would be appreciated.
Thanks
Hi.
I need to use a relay server to send email. there is no user and no sender account.
but the library looks like its you need to auth every time.
It would be nice to be able to export gomail.Message to []byte. I would suggest a function Raw() []byte on Message.
I could implement this and make a pull request.
I'd like to generate an email with a body and an attachment where each uses a different Content-Transfer-Encoding. Is this possible? It seems that each message part takes the value for the Content-Transfer-Encoding from the Message
object's value for encoding
, and are not independently settable.
Specifically, I want the body to have a Content-Type of "text/plain; format=flowed" with a Content-Transfer-Encoding of "8bit", and the attachment to have a Content-Type of "text/html" but with a Content-Transfer-Encoding of "quoted-printable". (I'd rather not have the format=flowed text be encoded as quoted-printable, since RFC 3676 says that it "should not" be so.)
I'm fine with manually encoding the data I give to SetBody
and AddAlternative
as 8bit and quoted-printable, respectively; I just need to be able set the Content-Transfer-Encoding on a per-part basis.
Is there a way to do that now? If not, does it seem like a reasonable thing to be able to do?
Thanks for any help.
As per RFC822, email messages should have a Message-ID field.
I know it's the message creator's responsibility, but at least we could help him by including a MakeMsgID function, as in https://github.com/tgulacsi/go/blob/master/i18nmail/msgid.go ?
If it's easier on you, I can send it as a PR, but first please vet this suggestion.
Hi!
My proxy server as 10.0.2.251 (squid).
Users as 10.0.0.*
If user send without proxy, connect failed. How i can use gomail
with proxy? Sorry for my bad english.
undefined: tls in tls.Config
go build teste_email.go
./teste_email.go:16: undefined: tls in tls.Config
Hello,
SpamAssassin report an invalid date header with mail sent with Gomail because it's not RFC 2822.
It is currently set to time.RFC822Z : https://github.com/go-gomail/gomail/blob/master/gomail.go#L147
See https://wiki.apache.org/spamassassin/Rules/INVALID_DATE
Regards
somehow running the go get gopkg.in/gomail.v1
in centos 6 is not working.. it just stuck there for very very long.
and i check the $GOPATH/src/gopkg.in folder its empty...
and i have been very curious why is it not go get github.com/go-gomail/gomail instead...
Hi,
Just tried to use this package but get the following error:
$ go get gopkg.in/gomail.v1
# gopkg.in/alexcesaro/quotedprintable.v1
/home/src/gopkg.in/alexcesaro/quotedprintable.v1/header.go:76: undefined: sync.Pool
$
$ go version
go version go1.2.1 linux/amd64
Am I doing something wrong?
Thanks
Best regards
Mario
Hey!
Could be me doing something wrong, but whenever I set the From
header with FormatAddress
function I get panic: 555 5.5.2 Syntax error. u8sm2660708wjq.1 - gsmtp
from smtp.gmail.com
If I use the simple msg.SetHeader("From", "[email protected]")
format it works.
msg := gomail.NewMessage()
// msg.SetHeader("From", e.SenderMail)) // works
msg.SetHeader("From", msg.FormatAddress(e.SenderEmail, e.SenderName)) // error
msg.SetHeader("To", e.RecieverEmail)
msg.SetHeader("Subject", e.Subject)
msg.SetBody("text/html", e.Body)
mailer := gomail.NewMailer("smtp.gmail.com", "[email protected]", "password", 587)
if err := mailer.Send(msg); err != nil {
panic(err)
}
Its often convenient to send both text/html
and text/plain
: pretty emails for those that support it, and basic emails for those that don't.
msg := gomail.NewMessage()
msg.SetBody("text/plain", "Hello!")
msg.SetBody("text/html", "<b>Hello!</b>")
However, the second SetBody
, replaces the first.
I always get a EOF error.
I have tcpdumped the traffic.
The connect is reset when it using tls.
When calling FormatAddress
with an empty name, like:
FormatAddress("[email protected]", "")
It returns:
"" <[email protected]>
But it would be better to return:
Normally it wouldn't matter all that much, but there is a bug in Go 1.5 and up that rejects such addresses with an error: golang/go#14866
Removing the redundant ""
would greatly help work around this Go bug.
In the meantime, a hack like this will work around it:
if name == "" {
message.SetHeader("To", address) // bypass FormatAddress altogether
} else {
message.SetAddressHeader("To", address, name)
}
dialandsend return an error when inside a privileged docker container
When inside a kubernetes, the error does not seem to happen, but the email do not get sended.
web_1 | /api/register
web_1 | 172.18.0.1 - - [10/Apr/2016:20:51:59 +0000] "POST /api/register HTTP/1.1" 200 78
web_1 | http://localhost:9001/api/confirm/$2a$04$6Dad45u6SlTB7rWTNz2GzOc3j9jWOjT.1oTjfuvO5Bd8gKGwnvX56
web_1 | panic: x509: failed to load system roots and no roots provided
web_1 |
web_1 | goroutine 49 [running]:
web_1 | panic(0x9f49c0, 0xe2e628)
web_1 | /usr/lib/go/src/runtime/panic.go:464 +0x3e6
web_1 | bitbucket.org/cescoferraro/templatego/src/backend/api.SendRegisterEmail(0xc820210b60, 0x0, 0x0, 0xc8201f99d0, 0x9, 0xc8201fd540, 0x1b, 0xc820200b00, 0x3c, 0x0, ...)
web_1 | /home/cesco/code/go/src/bitbucket.org/cescoferraro/templatego/src/backend/api/register.go:85 +0x7af
web_1 | created by bitbucket.org/cescoferraro/templatego/src/backend/api.RegisterEndPoint
web_1 | /home/cesco/code/go/src/bitbucket.org/cescoferraro/templatego/src/backend/api/register.go:55 +0x656
templatego_web_1 exited with code 2
Hi, This library crashes at writeto.go file line no: 164 with error "panic: runtime error: index out of range". I would suggest to return from 'writeStrings' functions if len(a) <= 0.
When constructing -> parsing -> re-constructing a message it is difficult to re-create the same message since message.WriteTo()
iterates through a map and the order of headers is random. In some instances the order of the headers matters such as DKIM and Received headers. Would you be interested in a PR to support this? If so, I see it two ways:
Use a slice instead of a map (like attachments) to preserve order. Unfortunately, message.SetHeaders
signature will change.
Change the type of header from map[string][]string
to something like map[string]*hValue
where hValue
is something like:
type hValue struct {
values []string
order int
}
order
increments each time a header gets added. Then message.WriteTo
will sort headers by order
when writing headers.
Let me know what you think, thanks.
I use gmail account to send a email,but it return a error with a warning.
I can fixed it by turn off some secure stuff.
https://support.google.com/accounts/answer/6010255?hl=en
Can this stuff be fixed in this library?
Hi,
as far as I understood your code you implement the smtp.Auth interface which is then used by the smtp package when calling c.Auth().
In auth.go you implement LOGIN and PLAIN mechanisms. Have you ever thought about implementing CRAM-MD5?
You would have to return CRAM-MD5 in Auth.Send, listen for the base64 encoded challenge in Auth.Next, decode it and return (base64 encoded) the username and a MD5 response à la
digest = MD5(('password' XOR opad), MD5(('password' XOR ipad), challenge))
.
From golang-nuts: https://groups.google.com/d/msg/golang-nuts/ywPpNlmSt6U/0Mxttkx9kgQJ
mailer := gomail.NewMailer("smtp.office365.com", "[email protected]", "password", 587)
Returns error 504 5.7.4 Unrecognized authentication type
Currently the a Message is only checked for validity when it is sent and all the logic for validation is in the Mailer.Send() function. It seems that this might be more useful to pull put either into it's own set of functions or as a function of the Message struct.
This would be useful when you want to check the validity of a message without sending it. - i.e. check that a message is valid and present a user of what they need to fix if it isn't.
When I try to go get
gomail, it fails due to one of the project dependency:
$ go get gopkg.in/gomail.v1
# gopkg.in/alexcesaro/quotedprintable.v1
gopkg.in/alexcesaro/quotedprintable.v1/header.go:76: undefined: sync.Pool
I checked and it appears that sync.Pool
does not exist exist in Go 1.2
My version of Go:
go version
go version go1.2.1 linux/amd64
I'm currently looking for a golang replacement for Haraka SMTP server. Is this an SMTP server or a library that would call an SMTP server?
Haraka:
https://haraka.github.io/
Hi!
Currently, I'm using msg.SetAddressHeader("Bcc", emailBcc, "bcc")
to copy someone while hiding its address. Is the right way to do that? How can I copy more people?
Thanks!
Here's a small Golang program which demonstrates the problem:
package main
import (
"gopkg.in/gomail.v2"
"os"
)
func main() {
m := gomail.NewMessage()
m.SetHeader("From", "[email protected]")
m.SetHeader("To", "[email protected]")
m.SetHeader("Subject", "{$firstname} Bienvendio a Apostólica, aquí inicia el camino de tu")
m.SetBody("text/plain", "Hello, World")
m.WriteTo(os.Stdout)
}
This program will output these headers:
Mime-Version: 1.0
Date: Wed, 16 Mar 2016 09:08:29 -0400
From: [email protected]
To: [email protected]
Subject: =?UTF-8?q?{$firstname}_Bienvendio_a_Apost=C3=B3lica,_aqu=C3=AD_inicia_el_camino_de_tu?=
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Note that the Subject
header line is 96 characters long. According to RFC 2047,
While there is no limit to the length of a multiple-line header
field, each line of a header field that contains one or more
'encoded-word's is limited to 76 characters.
The Subject
header should have been folded at 76 characters but it was not.
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.