Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Golang SSL SMTP Example
package main
import (
"fmt"
"log"
"net"
"net/mail"
"net/smtp"
"crypto/tls"
)
// SSL/TLS Email Example
func main() {
from := mail.Address{"", "username@example.tld"}
to := mail.Address{"", "username@anotherexample.tld"}
subj := "This is the email subject"
body := "This is an example body.\n With two lines."
// Setup headers
headers := make(map[string]string)
headers["From"] = from.String()
headers["To"] = to.String()
headers["Subject"] = subj
// Setup message
message := ""
for k,v := range headers {
message += fmt.Sprintf("%s: %s\r\n", k, v)
}
message += "\r\n" + body
// Connect to the SMTP Server
servername := "smtp.example.tld:465"
host, _, _ := net.SplitHostPort(servername)
auth := smtp.PlainAuth("","username@example.tld", "password", host)
// TLS config
tlsconfig := &tls.Config {
InsecureSkipVerify: true,
ServerName: host,
}
// Here is the key, you need to call tls.Dial instead of smtp.Dial
// for smtp servers running on 465 that require an ssl connection
// from the very beginning (no starttls)
conn, err := tls.Dial("tcp", servername, tlsconfig)
if err != nil {
log.Panic(err)
}
c, err := smtp.NewClient(conn, host)
if err != nil {
log.Panic(err)
}
// Auth
if err = c.Auth(auth); err != nil {
log.Panic(err)
}
// To && From
if err = c.Mail(from.Address); err != nil {
log.Panic(err)
}
if err = c.Rcpt(to.Address); err != nil {
log.Panic(err)
}
// Data
w, err := c.Data()
if err != nil {
log.Panic(err)
}
_, err = w.Write([]byte(message))
if err != nil {
log.Panic(err)
}
err = w.Close()
if err != nil {
log.Panic(err)
}
c.Quit()
}
@horrido

This comment has been minimized.

Show comment Hide comment
@horrido

horrido Aug 16, 2014

This is a wonderful example you've provided. (Thank you very much!) However, it doesn't work. I get the following error message:

2014/08/16 07:44:45 tls: first record does not look like a TLS handshake
panic: tls: first record does not look like a TLS handshake

goroutine 16 [running]:
runtime.panic(0x18d660, 0xc2080005a0)
/usr/local/go/src/pkg/runtime/panic.c:279 +0xf5
log.Panic(0x671e30, 0x1, 0x1)
/usr/local/go/src/pkg/log/log.go:307 +0xb6
main.main()
/Users/richardeng/fred.go:52 +0x7a9

Line 52, as in your example, refers to the tls.Dial() call. What's wrong??

(FYI, the servername I'm using is "smtp.gmail.com:587".)

horrido commented Aug 16, 2014

This is a wonderful example you've provided. (Thank you very much!) However, it doesn't work. I get the following error message:

2014/08/16 07:44:45 tls: first record does not look like a TLS handshake
panic: tls: first record does not look like a TLS handshake

goroutine 16 [running]:
runtime.panic(0x18d660, 0xc2080005a0)
/usr/local/go/src/pkg/runtime/panic.c:279 +0xf5
log.Panic(0x671e30, 0x1, 0x1)
/usr/local/go/src/pkg/log/log.go:307 +0xb6
main.main()
/Users/richardeng/fred.go:52 +0x7a9

Line 52, as in your example, refers to the tls.Dial() call. What's wrong??

(FYI, the servername I'm using is "smtp.gmail.com:587".)

@spagettikod

This comment has been minimized.

Show comment Hide comment
@spagettikod

spagettikod Nov 17, 2014

Thanks for the great example! Worked for me "out of the box" using AWS SES.

Thanks for the great example! Worked for me "out of the box" using AWS SES.

@rosscanning

This comment has been minimized.

Show comment Hide comment
@rosscanning

rosscanning Nov 22, 2014

Thanks a bunch, Chris. Very useful.

@horrido: Didn't work for me either on gmail (same error message). I don't know why, but it worked fine with the two other mail services I tried it with. It's weird that it doesn't work with Gmail, of all services!

Thanks a bunch, Chris. Very useful.

@horrido: Didn't work for me either on gmail (same error message). I don't know why, but it worked fine with the two other mail services I tried it with. It's weird that it doesn't work with Gmail, of all services!

@EngelbertHumperdinck

This comment has been minimized.

Show comment Hide comment
@EngelbertHumperdinck

EngelbertHumperdinck Dec 3, 2014

Which mail services does it work with?

Which mail services does it work with?

@vvelikodny

This comment has been minimized.

Show comment Hide comment
@vvelikodny

vvelikodny Jan 22, 2015

It works for Gmail out of the box, thanks!

It works for Gmail out of the box, thanks!

@drewlesueur

This comment has been minimized.

Show comment Hide comment
@drewlesueur

drewlesueur Feb 5, 2015

This rocks. Thank you. Ps. If you are using rackspace email, this will help with what servers to use http://www.rackspace.com/apps/support/portal/1088

This rocks. Thank you. Ps. If you are using rackspace email, this will help with what servers to use http://www.rackspace.com/apps/support/portal/1088

@alecha

This comment has been minimized.

Show comment Hide comment
@alecha

alecha Jul 10, 2015

Works with Amazon SES only if using port 465, thanks ;)

alecha commented Jul 10, 2015

Works with Amazon SES only if using port 465, thanks ;)

@arteev

This comment has been minimized.

Show comment Hide comment
@arteev

arteev Aug 9, 2015

It works for Yandex. Thanks!

arteev commented Aug 9, 2015

It works for Yandex. Thanks!

@PeterBooker

This comment has been minimized.

Show comment Hide comment
@PeterBooker

PeterBooker Sep 1, 2015

This was very useful, thank you.

This was very useful, thank you.

@kennwhite

This comment has been minimized.

Show comment Hide comment
@kennwhite

kennwhite Nov 30, 2015

Curious, why are you disabling peer verification? (https://gist.github.com/chrisgillis/10888032#file-ssl_smtp_example-go-L43) That allows MitM and sort of obviates the whole point of forcing TLS.
Btw, the example here: https://golang.org/pkg/net/smtp/#example_SendMail (Example/SendMail) is much shorter, and if used with Amazon SES endpoint specified as port 587, will use StartTLS.

Curious, why are you disabling peer verification? (https://gist.github.com/chrisgillis/10888032#file-ssl_smtp_example-go-L43) That allows MitM and sort of obviates the whole point of forcing TLS.
Btw, the example here: https://golang.org/pkg/net/smtp/#example_SendMail (Example/SendMail) is much shorter, and if used with Amazon SES endpoint specified as port 587, will use StartTLS.

@DaveAppleton

This comment has been minimized.

Show comment Hide comment
@DaveAppleton

DaveAppleton May 16, 2016

Hi Dave,
Someone just tried to sign in to your Google Account xxxx@gmail.com from an app that doesn't meet modern security standards.

Hi Dave,
Someone just tried to sign in to your Google Account xxxx@gmail.com from an app that doesn't meet modern security standards.

@suntong

This comment has been minimized.

Show comment Hide comment
@suntong

suntong May 28, 2016

Thanks for the great example! Worked for me "out of the box" for aliyun.
I avoided gmail because the very problem DaveAppleton mentioned.

suntong commented May 28, 2016

Thanks for the great example! Worked for me "out of the box" for aliyun.
I avoided gmail because the very problem DaveAppleton mentioned.

@mappenzellar

This comment has been minimized.

Show comment Hide comment
@mappenzellar

mappenzellar Jun 27, 2016

How would you integrate attachments into this?

How would you integrate attachments into this?

@picasso250

This comment has been minimized.

Show comment Hide comment
@picasso250

picasso250 Jul 15, 2016

It works for QQ mail, and thanks very very much!

It works for QQ mail, and thanks very very much!

@helgigit

This comment has been minimized.

Show comment Hide comment
@helgigit

helgigit Jul 18, 2016

Thanks! Works for smtp.zoho.com

Thanks! Works for smtp.zoho.com

@myafeier

This comment has been minimized.

Show comment Hide comment
@myafeier

myafeier Jul 25, 2016

Thanks Works for smtp.mxhichina.com

Thanks Works for smtp.mxhichina.com

@cruiz1391

This comment has been minimized.

Show comment Hide comment
@cruiz1391

cruiz1391 Sep 26, 2016

I am getting "Msg": "first record does not look like a TLS handshake", using office365 (smtp.office365.com:587)

I am getting "Msg": "first record does not look like a TLS handshake", using office365 (smtp.office365.com:587)

@emacsist

This comment has been minimized.

Show comment Hide comment
@emacsist

emacsist Nov 29, 2016

Nice

Nice

@paulburlumi

This comment has been minimized.

Show comment Hide comment
@paulburlumi

paulburlumi Jan 31, 2017

@cruiz1391 See the discussion here for a solution using office365
mattermost/platform#954
golang/go#9899
Using the workaround for AUTH LOGIN worked for me.

@cruiz1391 See the discussion here for a solution using office365
mattermost/platform#954
golang/go#9899
Using the workaround for AUTH LOGIN worked for me.

@JIElite

This comment has been minimized.

Show comment Hide comment
@JIElite

JIElite Feb 2, 2017

Thank you for sharing
It do works for AWS SES!

just modify

  1. servername: endpoint, like: email-smtp.us-west-2.amazonaws.com:465
  2. smtp.PlainAuth username: IAM username
  3. smtp.PlainAuth password: IAM password

Thank you for shaing!

JIElite commented Feb 2, 2017

Thank you for sharing
It do works for AWS SES!

just modify

  1. servername: endpoint, like: email-smtp.us-west-2.amazonaws.com:465
  2. smtp.PlainAuth username: IAM username
  3. smtp.PlainAuth password: IAM password

Thank you for shaing!

@JoelTrottier

This comment has been minimized.

Show comment Hide comment
@JoelTrottier

JoelTrottier Aug 30, 2017

Referred to this code for sending Yahoo! mail: smtp.mail.yahoo.com:465
Worked as intended. Thanks!

If you get this error:
(#MBR1212) Incorrect username or password.

Make sure you toggle this Account Security option in your Yahoo! account settings:
Allow apps that use less secure sign in

JoelTrottier commented Aug 30, 2017

Referred to this code for sending Yahoo! mail: smtp.mail.yahoo.com:465
Worked as intended. Thanks!

If you get this error:
(#MBR1212) Incorrect username or password.

Make sure you toggle this Account Security option in your Yahoo! account settings:
Allow apps that use less secure sign in

@jumping

This comment has been minimized.

Show comment Hide comment
@jumping

jumping Mar 29, 2018

The libexec/src/net/smtp/smtp.go has similar code, in the func SendMail.

jumping commented Mar 29, 2018

The libexec/src/net/smtp/smtp.go has similar code, in the func SendMail.

@gjedeer

This comment has been minimized.

Show comment Hide comment
@gjedeer

gjedeer Apr 12, 2018

To the people getting "first record does not look like a TLS handshake" on port 587: use port 465 instead, if your provider supports it.

Port 465 is TLS-only, which means: the client connects and immediately establishes a TLS handshake. Just like with HTTPS. This kind of connection is often incorrectly named "SSL" by email providers.

Port 587 is a cleartext SMTP port. This means that the client connects, introduces itself in plaintext, then sends a STARTTLS command and TLS handshake happens. This kind of connection is incorrectly named "TLS" by email providers.

If your provider doesn't support "SSL" connections (port 465), you're going to need to use another provider (or find an example using the StartTLS function)

gjedeer commented Apr 12, 2018

To the people getting "first record does not look like a TLS handshake" on port 587: use port 465 instead, if your provider supports it.

Port 465 is TLS-only, which means: the client connects and immediately establishes a TLS handshake. Just like with HTTPS. This kind of connection is often incorrectly named "SSL" by email providers.

Port 587 is a cleartext SMTP port. This means that the client connects, introduces itself in plaintext, then sends a STARTTLS command and TLS handshake happens. This kind of connection is incorrectly named "TLS" by email providers.

If your provider doesn't support "SSL" connections (port 465), you're going to need to use another provider (or find an example using the StartTLS function)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment