]>
src.bluestatic.org Git - mailpopbox.git/blob - smtp/relay.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
17 func RelayMessage(server Server
, env Envelope
, log
*zap
.Logger
) {
18 for _
, rcptTo
:= range env
.RcptTo
{
19 sendLog
:= log
.With(zap
.String("address", rcptTo
.Address
))
21 domain
:= DomainForAddress(rcptTo
)
22 mx
, err
:= net
.LookupMX(domain
)
23 if err
!= nil ||
len(mx
) < 1 {
24 sendLog
.Error("failed to lookup MX records",
26 deliverRelayFailure(env
, err
)
29 host
:= mx
[0].Host
+ ":25"
30 relayMessageToHost(server
, env
, sendLog
, rcptTo
.Address
, host
)
34 func relayMessageToHost(server Server
, env Envelope
, log
*zap
.Logger
, to
, host
string) {
35 from
:= env
.MailFrom
.Address
37 c
, err
:= smtp
.Dial(host
)
39 // TODO - retry, or look at other MX records
40 log
.Error("failed to dial host",
41 zap
.String("host", host
),
43 deliverRelayFailure(env
, err
)
48 log
= log
.With(zap
.String("host", host
))
50 if err
= c
.Hello(server
.Name()); err
!= nil {
51 log
.Error("failed to HELO", zap
.Error(err
))
52 deliverRelayFailure(env
, err
)
56 if hasTls
, _
:= c
.Extension("STARTTLS"); hasTls
{
57 config
:= &tls
.Config
{ServerName
: host
}
58 if err
= c
.StartTLS(config
); err
!= nil {
59 log
.Error("failed to STARTTLS", zap
.Error(err
))
60 deliverRelayFailure(env
, err
)
65 if err
= c
.Mail(from
); err
!= nil {
66 log
.Error("failed MAIL FROM", zap
.Error(err
))
67 deliverRelayFailure(env
, err
)
71 if err
= c
.Rcpt(to
); err
!= nil {
72 log
.Error("failed to RCPT TO", zap
.Error(err
))
73 deliverRelayFailure(env
, err
)
79 log
.Error("failed to DATA", zap
.Error(err
))
80 deliverRelayFailure(env
, err
)
84 _
, err
= wc
.Write(env
.Data
)
87 log
.Error("failed to write DATA", zap
.Error(err
))
88 deliverRelayFailure(env
, err
)
92 if err
= wc
.Close(); err
!= nil {
93 log
.Error("failed to close DATA", zap
.Error(err
))
94 deliverRelayFailure(env
, err
)
99 func deliverRelayFailure(env Envelope
, err error
) {
100 // TODO: constructo a delivery status notification