Skip to content

Commit

Permalink
added source files
Browse files Browse the repository at this point in the history
  • Loading branch information
ungerik committed Mar 24, 2012
1 parent 9af9327 commit 532167d
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 0 deletions.
25 changes: 25 additions & 0 deletions address.go
@@ -0,0 +1,25 @@
package email

import (
"errors"
"regexp"
"strings"
)

var emailRegexp *regexp.Regexp

func NormalizeAddress(address string) string {
return strings.ToLower(strings.TrimSpace(address))
}

func ValidateAddress(address string) (normalizedAddress string, err error) {
if emailRegexp == nil {
emailRegexp = regexp.MustCompile("[a-z0-9.\\-_%]+@[a-z0-9.\\-]+\\.[a-z][a-z]+")
}
normalizedAddress = NormalizeAddress(address)
valid := emailRegexp.Match([]byte(normalizedAddress))
if !valid {
return "", errors.New("Invalid email address: " + address)
}
return normalizedAddress, nil
}
37 changes: 37 additions & 0 deletions config.go
@@ -0,0 +1,37 @@
package email

import "net/mail"

type Configuration struct {
Host string
Port uint16
Username string
Password string
DefaultFrom mail.Address
}

var Config Configuration

func InitGmail(email, password string) error {
return InitGmailFrom(email, email, password)
}

// InitGmailFrom uses a different fromAddress for sending emails
// than the loginAddress used together with the password for authentication
// The fromAddress has to be verified as a valid sender address in Gmail.
func InitGmailFrom(fromAddress, loginAddress, password string) error {
if _, err := ValidateAddress(fromAddress); err != nil {
return err
}
if _, err := ValidateAddress(loginAddress); err != nil {
return err
}
Config = Configuration{
Host: "smtp.gmail.com",
Port: 587,
Username: loginAddress,
Password: password,
DefaultFrom: mail.Address{"", fromAddress},
}
return nil
}
2 changes: 2 additions & 0 deletions doc.go
@@ -0,0 +1,2 @@
// Utilities to make sending emails easier.
package email
93 changes: 93 additions & 0 deletions message.go
@@ -0,0 +1,93 @@
package email

import (
"bytes"
"errors"
"fmt"
"net/mail"
"net/smtp"
"time"
)

func NewBriefMessage(subject, content string, to ...string) *Message {
message := &Message{Subject: subject, Content: content, To: make([]mail.Address, len(to))}
for i := range to {
message.To[i].Address = to[i]
}
return message
}

func NewBriefMessageFrom(subject, content, from string, to ...string) *Message {
message := NewBriefMessage(subject, content, to...)
message.From.Address = from
return message
}

const crlf = "\r\n"

type Message struct {
From mail.Address // if From.Address is empty, Config.DefaultFrom will be used
To []mail.Address
Cc []mail.Address
Bcc []mail.Address
Subject string
Content string
}

// http://tools.ietf.org/html/rfc822
// http://tools.ietf.org/html/rfc2821
func (self *Message) String() string {
var buf bytes.Buffer

write := func(what string, recipients []mail.Address) {
if len(recipients) == 0 {
return
}
for i := range recipients {
if i == 0 {
buf.WriteString(what)
} else {
buf.WriteString(", ")
}
buf.WriteString(recipients[i].String())
}
buf.WriteString(crlf)
}

from := &self.From
if from.Address == "" {
from = &Config.DefaultFrom
}
fmt.Fprintf(&buf, "From: %s%s", from.String(), crlf)
write("To: ", self.To)
write("Cc: ", self.Cc)
write("Bcc: ", self.Bcc)
fmt.Fprintf(&buf, "Date: %s%s", time.Now().UTC().Format(time.RFC822), crlf)
fmt.Fprintf(&buf, "Subject: %s%s%s", self.Subject, crlf, self.Content)
return buf.String()
}

// Returns the first error
func (self *Message) Validate() error {
if len(self.To) == 0 {
return errors.New("Missing email recipient (email.Message.To)")
}
return nil
}

func (self *Message) Send() error {
if err := self.Validate(); err != nil {
return err
}
to := make([]string, len(self.To))
for i := range self.To {
to[i] = self.To[i].Address
}
from := self.From.Address
if from == "" {
from = Config.DefaultFrom.Address
}
addr := fmt.Sprintf("%s:%d", Config.Host, Config.Port)
auth := smtp.PlainAuth("", Config.Username, Config.Password, Config.Host)
return smtp.SendMail(addr, auth, from, to, []byte(self.String()))
}

0 comments on commit 532167d

Please sign in to comment.