152 lines
3.5 KiB
Markdown
152 lines
3.5 KiB
Markdown
# go-smtp
|
|
|
|
[](https://godocs.io/github.com/emersion/go-smtp)
|
|
[](https://builds.sr.ht/~emersion/go-smtp/commits?)
|
|
[](https://codecov.io/gh/emersion/go-smtp)
|
|
|
|
An ESMTP client and server library written in Go.
|
|
|
|
## Features
|
|
|
|
* ESMTP client & server implementing [RFC 5321](https://tools.ietf.org/html/rfc5321)
|
|
* Support for SMTP [AUTH](https://tools.ietf.org/html/rfc4954) and [PIPELINING](https://tools.ietf.org/html/rfc2920)
|
|
* UTF-8 support for subject and message
|
|
* [LMTP](https://tools.ietf.org/html/rfc2033) support
|
|
|
|
## Usage
|
|
|
|
### Client
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"log"
|
|
"strings"
|
|
|
|
"github.com/emersion/go-sasl"
|
|
"github.com/emersion/go-smtp"
|
|
)
|
|
|
|
func main() {
|
|
// Set up authentication information.
|
|
auth := sasl.NewPlainClient("", "user@example.com", "password")
|
|
|
|
// Connect to the server, authenticate, set the sender and recipient,
|
|
// and send the email all in one step.
|
|
to := []string{"recipient@example.net"}
|
|
msg := strings.NewReader("To: recipient@example.net\r\n" +
|
|
"Subject: discount Gophers!\r\n" +
|
|
"\r\n" +
|
|
"This is the email body.\r\n")
|
|
err := smtp.SendMail("mail.example.com:25", auth, "sender@example.org", to, msg)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
```
|
|
|
|
If you need more control, you can use `Client` instead.
|
|
|
|
### Server
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"io/ioutil"
|
|
"log"
|
|
"time"
|
|
|
|
"github.com/emersion/go-smtp"
|
|
)
|
|
|
|
// The Backend implements SMTP server methods.
|
|
type Backend struct{}
|
|
|
|
// Login handles a login command with username and password.
|
|
func (bkd *Backend) Login(state *smtp.ConnectionState, username, password string) (smtp.Session, error) {
|
|
if username != "username" || password != "password" {
|
|
return nil, errors.New("Invalid username or password")
|
|
}
|
|
return &Session{}, nil
|
|
}
|
|
|
|
// AnonymousLogin requires clients to authenticate using SMTP AUTH before sending emails
|
|
func (bkd *Backend) AnonymousLogin(state *smtp.ConnectionState) (smtp.Session, error) {
|
|
return nil, smtp.ErrAuthRequired
|
|
}
|
|
|
|
// A Session is returned after successful login.
|
|
type Session struct{}
|
|
|
|
func (s *Session) Mail(from string, opts smtp.MailOptions) error {
|
|
log.Println("Mail from:", from)
|
|
return nil
|
|
}
|
|
|
|
func (s *Session) Rcpt(to string) error {
|
|
log.Println("Rcpt to:", to)
|
|
return nil
|
|
}
|
|
|
|
func (s *Session) Data(r io.Reader) error {
|
|
if b, err := ioutil.ReadAll(r); err != nil {
|
|
return err
|
|
} else {
|
|
log.Println("Data:", string(b))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *Session) Reset() {}
|
|
|
|
func (s *Session) Logout() error {
|
|
return nil
|
|
}
|
|
|
|
func main() {
|
|
be := &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.Fatal(err)
|
|
}
|
|
}
|
|
```
|
|
|
|
You can use the server manually with `telnet`:
|
|
```
|
|
$ telnet localhost 1025
|
|
EHLO localhost
|
|
AUTH PLAIN
|
|
AHVzZXJuYW1lAHBhc3N3b3Jk
|
|
MAIL FROM:<root@nsa.gov>
|
|
RCPT TO:<root@gchq.gov.uk>
|
|
DATA
|
|
Hey <3
|
|
.
|
|
```
|
|
|
|
## Relationship with net/smtp
|
|
|
|
The Go standard library provides a SMTP client implementation in `net/smtp`.
|
|
However `net/smtp` is frozen: it's not getting any new features. go-smtp
|
|
provides a server implementation and a number of client improvements.
|
|
|
|
## Licence
|
|
|
|
MIT
|