My goal is to create a SMTP server to send an email from noreply@myname.com containing OTP.
The problem is, I code on my personal computer. Therefore, no public address or domain, yet. I tried to send email to myname@gmail.com, but I can't find it on the spam, or the inbox folders.
What I've did:
- run the go-smtp server.
$ go run cmd/server/main.go - run the go-smtp client.
$ go run cmd/client/main.go
The go-smtp server output
(base) jason@Jasons-Mac-mini server % go run main.go
2022/09/23 13:35:38 Starting server at :1025
2022/09/23 13:56:06 Mail from: test@localhost
2022/09/23 13:56:06 Rcpt to: // email redacted for stackoverflow
2022/09/23 13:56:06 Data: This is the email body
The go-smtp client output
(base) jason@Jasons-Mac-mini client % go run main.go
2022/09/23 13:56:06 Mail sent! time elapsed: 1.988625ms
cmd/client/main.go
package main
import (
"fmt"
"log"
"time"
"github.com/emersion/go-smtp"
)
func main() {
start := time.Now()
// Connect to the remote SMTP server.
c, err := smtp.Dial("localhost:1025")
if err != nil {
log.Fatal(err)
}
// Set the sender and recipient first
if err := c.Mail("test@localhost", nil); err != nil {
log.Fatal(err)
}
if err := c.Rcpt("jasonong713@gmail.com"); err != nil {
log.Fatal(err)
}
// Send the email body.
wc, err := c.Data()
if err != nil {
log.Fatal(err)
}
_, err = fmt.Fprintf(wc, "This is the email body")
if err != nil {
log.Fatal(err)
}
err = wc.Close()
if err != nil {
log.Fatal(err)
}
// Send the QUIT command and close the connection.
err = c.Quit()
if err != nil {
log.Fatal(err)
}
log.Println("Mail sent! time elapsed:", time.Since(start))
}
cmd/server/main.go
package main
import (
"log"
"time"
"github.com/emersion/go-smtp"
"github.com/godataid/sendemail"
)
func main() {
be := &sendemail.Backend{}
s := smtp.NewServer(be)
s.Addr = ":1025"
s.Domain = "localhost"
s.ReadTimeout = 10 * time.Second
s.WriteTimeout = 10 * time.Second
s.MaxMessageBytes = 1024 * 1024
s.MaxRecipients = 50
s.AllowInsecureAuth = true
log.Println("Starting server at", s.Addr)
if err := s.ListenAndServe(); err != nil {
log.Fatalln(err)
}
}
backend.go
package sendemail
import "github.com/emersion/go-smtp"
type Backend struct{}
// Authenticate a user. Return smtp.ErrAuthUnsupported if you don't want to
// support this.
func (be *Backend) Login(state *smtp.ConnectionState, username, password string) (smtp.Session, error) {
return nil, smtp.ErrAuthUnsupported
}
// Called if the client attempts to send mail without logging in first.
// Return smtp.ErrAuthRequired if you don't want to support this.
func (be *Backend) AnonymousLogin(state *smtp.ConnectionState) (smtp.Session, error) {
return &Session{}, nil
}
session.go
package sendemail
import (
"io"
"log"
"github.com/emersion/go-smtp"
)
type Session struct{}
// Discard currently processed message.
func (s *Session) Reset() {}
// Free all resources associated with session.
func (s *Session) Logout() error {
return nil
}
// Set return path for currently processed message.
func (s *Session) Mail(from string, opts smtp.MailOptions) error {
log.Println("Mail from:", from)
return nil
}
// Add recipient for currently processed message.
func (s *Session) Rcpt(to string) error {
log.Println("Rcpt to:", to)
return nil
}
// Set currently processed message contents and send it.
func (s *Session) Data(r io.Reader) error {
if b, err := io.ReadAll(r); err != nil {
return err
} else {
log.Println("Data:", string(b))
}
return nil
}