]>
src.bluestatic.org Git - mailpopbox.git/blob - smtp/server.go
2 // Copyright 2020 Blue Static <https://www.bluestatic.org>
3 // This program is free software licensed under the GNU General Public License,
4 // version 3.0. The full text of the license can be found in LICENSE.txt.
5 // SPDX-License-Identifier: GPL-3.0-only
23 type ReplyLine
struct {
28 func (l ReplyLine
) String() string {
29 return fmt
.Sprintf("%d %s", l
.Code
, l
.Message
)
32 var SendAsSubject
= regexp
.MustCompile(`(?i)\[sendas:\s*([a-zA-Z0-9\.\-_]+)\]`)
35 ReplyOK
= ReplyLine
{250, "OK"}
36 ReplyAuthOK
= ReplyLine
{235, "auth success"}
37 ReplyBadSyntax
= ReplyLine
{501, "syntax error"}
38 ReplyBadSequence
= ReplyLine
{503, "bad sequence of commands"}
39 ReplyBadMailbox
= ReplyLine
{550, "mailbox unavailable"}
40 ReplyMailboxUnallowed
= ReplyLine
{553, "mailbox name not allowed"}
43 func DomainForAddress(addr mail
.Address
) string {
44 return DomainForAddressString(addr
.Address
)
47 func DomainForAddressString(address
string) string {
48 domainIdx
:= strings
.LastIndex(address
, "@")
52 return address
[domainIdx
+1:]
55 type Envelope
struct {
65 func WriteEnvelopeForDelivery(w io
.Writer
, e Envelope
) {
66 fmt
.Fprintf(w
, "Delivered-To: <%s>\r\n", e
.RcptTo
[0].Address
)
67 fmt
.Fprintf(w
, "Return-Path: <%s>\r\n", e
.MailFrom
.Address
)
71 func generateEnvelopeId(prefix
string, t time
.Time
) string {
74 return fmt
.Sprintf("%s.%d.%x", prefix
, t
.UnixNano(), idBytes
)
77 // lookupRemoteHost attempts to reverse look-up the provided IP address. On
78 // success, it returns the hostname and the IP as formatted for a receive
79 // trace. If the lookup fails, it just returns the original IP.
80 func lookupRemoteHost(addr net
.Addr
) string {
81 rhost
, _
, err
:= net
.SplitHostPort(addr
.String())
86 rhosts
, err
:= net
.LookupAddr(rhost
)
88 rhost
= fmt
.Sprintf("%s [%s]", rhosts
[0], rhost
)
94 // Server provides an interface for handling incoming SMTP requests via
96 type Server
interface {
97 // Returns the name of the server, to use in HELO advertisements.
100 // If non-nil, enables STARTTLS support on the SMTP server with the given
102 TLSConfig() *tls
.Config
104 // Returns an status line indicating whether this server can receive
105 // mail for the specified email address.
106 VerifyAddress(mail
.Address
) ReplyLine
108 // Verify that the authc+passwd identity can send mail as authz on this
110 Authenticate(authz
, authc
, passwd
string) bool
112 // Delivers a valid incoming message to a recipient on this server. The
113 // addressee has been validated via VerifyAddress.
114 DeliverMessage(Envelope
) *ReplyLine
116 // RelayMessage instructs the server to send the Envelope to another
117 // MTA for outbound delivery.
118 RelayMessage(Envelope
)
121 // MTA (Mail Transport Agent) allows a Server to interface with other SMTP
124 // RelayMessage will attempt to send the specified Envelope. It will ask the
125 // Server to dial the MX servers for the addresses in Envelope.RcptTo for
126 // delivery. If relaying fails, a failure notice will be sent to the sender
127 // via Server.DeliverMessage.
128 RelayMessage(Envelope
)
131 func NewDefaultMTA(server Server
, log
*zap
.Logger
) MTA
{
143 type EmptyServerCallbacks
struct{}
145 func (*EmptyServerCallbacks
) TLSConfig() *tls
.Config
{
149 func (*EmptyServerCallbacks
) VerifyAddress(mail
.Address
) ReplyLine
{
153 func (*EmptyServerCallbacks
) Authenticate(authz
, authc
, passwd
string) bool {
157 func (*EmptyServerCallbacks
) DeliverMessage(Envelope
) *ReplyLine
{
161 func (*EmptyServerCallbacks
) RelayMessage(Envelope
) {