Skip to content

Instantly share code, notes, and snippets.

@mxey mxey/smtpd.go
Created Aug 12, 2012

Embed
What would you like to do?
package main
import (
"bytes"
"database/sql"
"errors"
"github.com/bradfitz/go-smtpd/smtpd"
_ "github.com/mattn/go-sqlite3"
"log"
)
type Mail struct {
*smtpd.BasicEnvelope
Sender string
Data bytes.Buffer
HeaderFinished bool
List MailingList
}
type MailingList struct {
id int
Addr string
ListIdHeader string
ReplyTo bool
}
var db *sql.DB
func GetMailingList(addr string) (MailingList, error) {
ml := MailingList{Addr: addr}
r := db.QueryRow("SELECT id, list_id_header, reply_to FROM lists WHERE addr = ?", addr)
if err := r.Scan(&ml.id, &ml.ListIdHeader, &ml.ReplyTo); err != nil {
if err == sql.ErrNoRows {
return ml, errors.New("Mailing list does not exist")
} else {
log.Fatal("Database query failed:", err)
}
}
return ml, nil
}
func (ml MailingList) HasMember(m string) bool {
r := db.QueryRow("SELECT 1 FROM members WHERE list_id = ? AND addr = ?", ml.id, m)
var x int
if err := r.Scan(&x); err != nil {
if err == sql.ErrNoRows {
return false
} else {
log.Fatal("Database query failed:", err)
}
}
return true
}
func (m *Mail) AddRecipient(rcpt smtpd.MailAddress) error {
rcptaddr := rcpt.Email()
ml, err := GetMailingList(rcptaddr)
if err != nil {
return smtpd.SMTPError("550 List does not exist")
}
if !ml.HasMember(m.Sender) {
return smtpd.SMTPError("550 Sender is not list member")
}
m.List = ml
return m.BasicEnvelope.AddRecipient(rcpt)
}
func (m *Mail) BeginData() error {
return nil
}
func (m *Mail) Write(line []byte) error {
if !m.HeaderFinished && bytes.Equal(line, []byte("\r\n")) {
// Last line of header, add list meta data
if _, err := m.Data.WriteString("List-Id: " + m.List.ListIdHeader + "\r\n"); err != nil {
return err
}
if _, err := m.Data.WriteString("List-Post: <mailto:" + m.List.Addr + ">\r\n"); err != nil {
return err
}
if m.List.ReplyTo {
if _, err := m.Data.WriteString("Reply-To: " + m.List.Addr + "\r\n"); err != nil {
return err
}
}
m.HeaderFinished = true
}
_, err := m.Data.Write(line)
return err
}
func (m *Mail) Close() error {
log.Print(m.Data.String())
return nil
}
func onNewMail(c smtpd.Connection, from smtpd.MailAddress) (smtpd.Envelope, error) {
return &Mail{BasicEnvelope: new(smtpd.BasicEnvelope), Sender: from.Email()}, nil
}
func main() {
var err error
db, err = sql.Open("sqlite3", "./lists.db")
if err != nil {
log.Fatal(err)
}
s := &smtpd.Server{
Addr: ":2500",
OnNewMail: onNewMail,
}
if err := s.ListenAndServe(); err != nil {
log.Fatalf("ListenAndServe: %v", err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.