- 
            
      
        
      
    Star
      
          
          (195)
      
  
You must be signed in to star a gist 
- 
              
      
        
      
    Fork
      
          
          (45)
      
  
You must be signed in to fork a gist 
- 
      
- 
        Save chrisgillis/10888032 to your computer and use it in GitHub Desktop. 
| package main | |
| import ( | |
| "fmt" | |
| "log" | |
| "net" | |
| "net/mail" | |
| "net/smtp" | |
| "crypto/tls" | |
| ) | |
| // SSL/TLS Email Example | |
| func main() { | |
| from := mail.Address{"", "[email protected]"} | |
| to := mail.Address{"", "[email protected]"} | |
| 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("","[email protected]", "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() | |
| } | 
Awesome, thanks for this!
This indeed works.
Appreaciated.
Generational answer 🫡
Passed on from debugger to debugger
Work well.
Works great!
Thanks a lot
This worked great for fastmail.com STMP. My tls config didn't require the insecure verify as well:
// TLS config
tlsconfig := &tls.Config{
	ServerName: host,
}
In case someone finds it useful, to send a HTML body, add the following headers:
body := "<html><body><h1>Hello World!</h1></body></html>"
headers["MIME-Version"] = "1.0"
headers["Content-Type"] = "text/html; charset=UTF-8"
// Setup message
message := ""
for k,v := range headers {
    message += fmt.Sprintf("%s: %s\r\n", k, v)
}
message += "\r\n" + bodyShould we make the protection for SMTP-header-injection more explicit? like:
https://www.geeksforgeeks.org/what-is-smtp-header-injection/
https://github.com/golang/go/blob/87ec2c959c73e62bfae230ef7efca11ec2a90804/src/net/smtp/smtp.go#L429
// Setup message
message := ""
for k, v := range headers {
	line := fmt.Sprintf("%s: %s", k, v)
	// security assurance: RFC 5321
	if err := validateLine(line); err != nil {
		return err
	}
	message += line + "\r\n"
}
message += "\r\n" + body
// validateLine checks to see if a line has CR or LF as per RFC 5321.
func validateLine(line string) error {
	if strings.ContainsAny(line, "\n\r") {
		return errors.New("[mailer] smtp: A line must not contain CR or LF")
	}
	return nil
}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.
Your suggestion worked for me! Thanks bro! Also thanks to @chrisgillis
This worked for me. Thanks a lot