mirror of
https://blitiri.com.ar/repos/chasquid
synced 2026-01-09 17:55:57 +00:00
aliases: Implement "via" aliases
This patch implements "via" aliases, which let us explicitly select a server to use for delivery. This feature is useful in different scenarios, such as a secondary MX server that forwards all incoming email to a primary. For now, it is experimental and the syntax and semantics are subject to change.
This commit is contained in:
@@ -8,4 +8,9 @@ type Courier interface {
|
||||
// Deliver mail to a recipient. Return the error (if any), and whether it
|
||||
// is permanent (true) or transient (false).
|
||||
Deliver(from string, to string, data []byte) (error, bool)
|
||||
|
||||
// Forward mail using the given servers.
|
||||
// Return the error (if any), and whether it is permanent (true) or
|
||||
// transient (false).
|
||||
Forward(from string, to string, data []byte, servers []string) (error, bool)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package courier
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
@@ -108,3 +109,11 @@ func sanitizeForMDA(s string) string {
|
||||
}
|
||||
return strings.Map(valid, s)
|
||||
}
|
||||
|
||||
var errForwardNotSupported = errors.New(
|
||||
"forwarding not supported by the MDA courier")
|
||||
|
||||
// Forward is not supported by the MDA courier.
|
||||
func (p *MDA) Forward(from string, to string, data []byte, servers []string) (error, bool) {
|
||||
return errForwardNotSupported, true
|
||||
}
|
||||
|
||||
@@ -123,3 +123,15 @@ func TestSanitize(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestForward(t *testing.T) {
|
||||
p := MDA{"thisdoesnotexist", nil, 1 * time.Minute}
|
||||
err, permanent := p.Forward(
|
||||
"from", "to", []byte("data"), []string{"server"})
|
||||
if err != errForwardNotSupported {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if !permanent {
|
||||
t.Errorf("expected permanent, got transient")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ func (s *SMTP) Deliver(from string, to string, data []byte) (error, bool) {
|
||||
to: to,
|
||||
toDomain: envelope.DomainOf(to),
|
||||
data: data,
|
||||
tr: trace.New("Courier.SMTP", to),
|
||||
tr: trace.New("Courier.SMTP.Deliver", to),
|
||||
}
|
||||
defer a.tr.Finish()
|
||||
a.tr.Debugf("%s -> %s", from, to)
|
||||
@@ -105,6 +105,42 @@ func (s *SMTP) Deliver(from string, to string, data []byte) (error, bool) {
|
||||
return a.tr.Errorf("all MXs returned transient failures (last: %v)", err), false
|
||||
}
|
||||
|
||||
// Forward an email. On failures, returns an error, and whether or not it is
|
||||
// permanent.
|
||||
func (s *SMTP) Forward(from string, to string, data []byte, servers []string) (error, bool) {
|
||||
a := &attempt{
|
||||
courier: s,
|
||||
from: from,
|
||||
to: to,
|
||||
toDomain: envelope.DomainOf(to),
|
||||
data: data,
|
||||
tr: trace.New("Courier.SMTP.Forward", to),
|
||||
}
|
||||
defer a.tr.Finish()
|
||||
a.tr.Debugf("%s -> %s", from, to)
|
||||
|
||||
// smtp.Client.Mail will add the <> for us when the address is empty.
|
||||
if a.from == "<>" {
|
||||
a.from = ""
|
||||
}
|
||||
|
||||
var err error
|
||||
for _, server := range servers {
|
||||
var permanent bool
|
||||
err, permanent = a.deliver(server)
|
||||
if err == nil {
|
||||
return nil, false
|
||||
}
|
||||
if permanent {
|
||||
return err, true
|
||||
}
|
||||
a.tr.Errorf("%q returned transient error: %v", server, err)
|
||||
}
|
||||
|
||||
// We exhausted all servers, try again later.
|
||||
return a.tr.Errorf("all servers returned transient failures (last: %v)", err), false
|
||||
}
|
||||
|
||||
type attempt struct {
|
||||
courier *SMTP
|
||||
|
||||
|
||||
Reference in New Issue
Block a user