|
package main |
|
|
|
import ( |
|
"errors" |
|
"log" |
|
"net/smtp" |
|
"os" |
|
"strings" |
|
) |
|
|
|
// Represents an email account. |
|
type Account struct { |
|
// Unexported |
|
auth smtp.Auth |
|
|
|
// Exported |
|
DisplayName string |
|
Address string |
|
} |
|
|
|
// Signs into an email account (linked to Gmail). |
|
func SignIn(displayName, username, password string) (*Account, error) { |
|
if displayName == "" { |
|
return nil, errors.New("displayName cannot be empty") |
|
} else if username == "" { |
|
return nil, errors.New("username cannot be empty") |
|
} else if password == "" { |
|
return nil, errors.New("password cannot be empty") |
|
} |
|
auth := smtp.PlainAuth("", username, password, "smtp.gmail.com") |
|
account := &Account{ |
|
auth: auth, |
|
DisplayName: displayName, |
|
Address: username, |
|
} |
|
return account, nil |
|
} |
|
|
|
type Draft struct { |
|
// Unexported |
|
auth smtp.Auth |
|
msg string |
|
|
|
// Exported |
|
From string |
|
To string |
|
Body string |
|
} |
|
|
|
// Returns a draft. |
|
func (a *Account) Compose(displayName, address, subject, body string) Draft { |
|
// https://golang.org/pkg/net/smtp/#example_SendMail |
|
// https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol#SMTP_transport_example |
|
from := a.DisplayName + " <" + a.Address + ">" |
|
to := displayName + " <" + address + ">" |
|
draft := Draft{ |
|
auth: a.auth, |
|
msg: "From:" + from + "\r\n" + |
|
"To: " + to + "\r\n" + |
|
"Subject: " + subject + "\r\n" + |
|
"\r\n" + |
|
body, |
|
From: a.Address, |
|
To: address, |
|
Body: body, |
|
} |
|
return draft |
|
} |
|
|
|
// Sends a draft. |
|
func (d Draft) Send() error { |
|
return smtp.SendMail("smtp.gmail.com:587", d.auth, d.From, []string{d.To}, []byte(d.msg)) |
|
} |
|
|
|
func must(err error) { |
|
if err == nil { |
|
// No-op |
|
return |
|
} |
|
log.Fatal(err) |
|
} |
|
|
|
type Receipient struct { |
|
displayName string |
|
address string |
|
firstName string |
|
} |
|
|
|
var receipients = []Receipient{ |
|
{ |
|
address: "[email protected]", |
|
displayName: "John Appleseed", |
|
firstName: "John", |
|
}, |
|
} |
|
|
|
func main() { |
|
// NOTE: This program requires temporarily enabling ‘Less |
|
// secure app access’ from Google. You can disable it |
|
// immediately after. |
|
// |
|
// https://myaccount.google.com/lesssecureapps |
|
user, err := SignIn(os.Getenv("DISPLAY_NAME"), os.Getenv("USERNAME"), os.Getenv("PASSWORD")) |
|
must(err) |
|
for _, r := range receipients { |
|
draft := user.Compose(r.displayName, r.address, "Hey "+r.firstName, strings.TrimSpace(` |
|
|
|
Hi `+r.firstName+`, |
|
|
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit… |
|
|
|
`)) |
|
must(draft.Send()) |
|
log.Printf("sent %s", draft.To) |
|
} |
|
} |