Skip to content

Instantly share code, notes, and snippets.

@noname007
Forked from xeoncross/mail.go
Created October 8, 2023 12:17
Show Gist options
  • Save noname007/6b43b6504ea738e0b25ad223b132b88c to your computer and use it in GitHub Desktop.
Save noname007/6b43b6504ea738e0b25ad223b132b88c to your computer and use it in GitHub Desktop.
Simple SMTP mail sender in golang that can send email directly to anyone. Super basic, but great for sending notice emails. Upgrades to STARTTLS if it can.
package main
import (
"encoding/base64"
"fmt"
"log"
"net"
"net/mail"
"net/smtp"
"strings"
"time"
)
// telnet gmail-smtp-in.l.google.com 25
// openssl s_client -connect gmail-smtp-in.l.google.com:25
func main() {
var (
mx string
err error
)
// Connect to the server, authenticate, set the sender and recipient,
// and send the email all in one step.
from := "me@example.com"
to := "bob@gmail.com"
subject := "Test Email"
body := "This is the email body at " + time.Now().String()
msg := composeMimeMail(to, from, subject, body)
mx, err = getMXRecord(to)
if err != nil {
log.Fatal(err)
}
err = smtp.SendMail(mx+":25", nil, from, []string{to}, msg)
if err != nil {
log.Fatal(err)
}
}
func getMXRecord(to string) (mx string, err error) {
var e *mail.Address
e, err = mail.ParseAddress(to)
if err != nil {
return
}
domain := strings.Split(e.Address, "@")[1]
var mxs []*net.MX
mxs, err = net.LookupMX(domain)
if err != nil {
return
}
for _, x := range mxs {
mx = x.Host
return
}
return
}
// Never fails, tries to format the address if possible
func formatEmailAddress(addr string) string {
e, err := mail.ParseAddress(addr)
if err != nil {
return addr
}
return e.String()
}
func encodeRFC2047(str string) string {
// use mail's rfc2047 to encode any string
addr := mail.Address{Address: str}
return strings.Trim(addr.String(), " <>")
}
func composeMimeMail(to string, from string, subject string, body string) []byte {
header := make(map[string]string)
header["From"] = formatEmailAddress(from)
header["To"] = formatEmailAddress(to)
header["Subject"] = encodeRFC2047(subject)
header["MIME-Version"] = "1.0"
header["Content-Type"] = "text/plain; charset=\"utf-8\""
header["Content-Transfer-Encoding"] = "base64"
message := ""
for k, v := range header {
message += fmt.Sprintf("%s: %s\r\n", k, v)
}
message += "\r\n" + base64.StdEncoding.EncodeToString([]byte(body))
return []byte(message)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment