mirror of
https://github.com/mjl-/mox.git
synced 2024-12-27 08:53:48 +03:00
for localserve, don't special-case smtp submit
the recent webmail addition added localserve local delivery in queue.Add, so we just that for smtpserver too. and don't drop incoming smtp deliver messages, but deliver as normal.
This commit is contained in:
parent
ce91b7d23e
commit
a30d8c1378
1 changed files with 49 additions and 109 deletions
|
@ -1752,102 +1752,43 @@ func (c *conn) submit(ctx context.Context, recvHdrFor func(string) string, msgWr
|
||||||
}
|
}
|
||||||
msgPrefix = append(msgPrefix, []byte(authResults.Header())...)
|
msgPrefix = append(msgPrefix, []byte(authResults.Header())...)
|
||||||
|
|
||||||
if Localserve {
|
// We always deliver through the queue. It would be more efficient to deliver
|
||||||
var timeout bool
|
// directly, but we don't want to circumvent all the anti-spam measures. Accounts
|
||||||
c.account.WithWLock(func() {
|
// on a single mox instance should be allowed to block each other.
|
||||||
for i, rcptAcc := range c.recipients {
|
for i, rcptAcc := range c.recipients {
|
||||||
var code int
|
if Localserve {
|
||||||
code, timeout = localserveNeedsError(rcptAcc.rcptTo.Localpart)
|
code, timeout := localserveNeedsError(rcptAcc.rcptTo.Localpart)
|
||||||
if timeout {
|
if timeout {
|
||||||
// Get out of wlock, and sleep there.
|
c.log.Info("timing out submission due to special localpart")
|
||||||
return
|
mox.Sleep(mox.Context, time.Hour)
|
||||||
} else if code != 0 {
|
xsmtpServerErrorf(codes{smtp.C451LocalErr, smtp.SeSys3Other0}, "timing out submission due to special localpart")
|
||||||
c.log.Info("failure due to special localpart", mlog.Field("code", code))
|
} else if code != 0 {
|
||||||
xsmtpServerErrorf(codes{code, smtp.SeOther00}, "failure with code %d due to special localpart", code)
|
c.log.Info("failure due to special localpart", mlog.Field("code", code))
|
||||||
}
|
xsmtpServerErrorf(codes{code, smtp.SeOther00}, "failure with code %d due to special localpart", code)
|
||||||
|
|
||||||
xmsgPrefix := append([]byte(recvHdrFor(rcptAcc.rcptTo.String())), msgPrefix...)
|
|
||||||
// todo: don't convert the headers to a body? it seems the body part is optional. does this have consequences for us in other places? ../rfc/5322:343
|
|
||||||
if !msgWriter.HaveHeaders {
|
|
||||||
xmsgPrefix = append(xmsgPrefix, "\r\n"...)
|
|
||||||
}
|
|
||||||
msgSize := int64(len(xmsgPrefix)) + msgWriter.Size
|
|
||||||
|
|
||||||
ipmasked1, ipmasked2, ipmasked3 := ipmasked(c.remoteIP)
|
|
||||||
m := store.Message{
|
|
||||||
Received: time.Now(),
|
|
||||||
RemoteIP: c.remoteIP.String(),
|
|
||||||
RemoteIPMasked1: ipmasked1,
|
|
||||||
RemoteIPMasked2: ipmasked2,
|
|
||||||
RemoteIPMasked3: ipmasked3,
|
|
||||||
EHLODomain: c.hello.Domain.Name(),
|
|
||||||
MailFrom: c.mailFrom.String(),
|
|
||||||
MailFromLocalpart: c.mailFrom.Localpart,
|
|
||||||
MailFromDomain: c.mailFrom.IPDomain.Domain.Name(),
|
|
||||||
RcptToLocalpart: rcptAcc.rcptTo.Localpart,
|
|
||||||
RcptToDomain: rcptAcc.rcptTo.IPDomain.Domain.Name(),
|
|
||||||
MsgFromLocalpart: msgFrom.Localpart,
|
|
||||||
MsgFromDomain: msgFrom.Domain.Name(),
|
|
||||||
MsgFromOrgDomain: publicsuffix.Lookup(ctx, msgFrom.Domain).Name(),
|
|
||||||
EHLOValidated: true,
|
|
||||||
MailFromValidated: true,
|
|
||||||
MsgFromValidated: true,
|
|
||||||
EHLOValidation: store.ValidationPass,
|
|
||||||
MailFromValidation: store.ValidationRelaxed,
|
|
||||||
MsgFromValidation: store.ValidationRelaxed,
|
|
||||||
DKIMDomains: nil,
|
|
||||||
Size: msgSize,
|
|
||||||
MsgPrefix: xmsgPrefix,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.account.Deliver(c.log, rcptAcc.destination, &m, dataFile, i == len(c.recipients)-1); err != nil {
|
|
||||||
// Aborting the transaction is not great. But continuing and generating DSNs will
|
|
||||||
// probably result in errors as well...
|
|
||||||
metricSubmission.WithLabelValues("localserveerror").Inc()
|
|
||||||
c.log.Errorx("delivering message", err)
|
|
||||||
xsmtpServerErrorf(errCodes(smtp.C451LocalErr, smtp.SeSys3Other0, err), "error delivering message: %v", err)
|
|
||||||
}
|
|
||||||
metricSubmission.WithLabelValues("ok").Inc()
|
|
||||||
c.log.Info("submitted message delivered", mlog.Field("mailfrom", *c.mailFrom), mlog.Field("rcptto", rcptAcc.rcptTo), mlog.Field("smtputf8", c.smtputf8), mlog.Field("msgsize", msgSize))
|
|
||||||
|
|
||||||
err := c.account.DB.Insert(ctx, &store.Outgoing{Recipient: rcptAcc.rcptTo.XString(true)})
|
|
||||||
xcheckf(err, "adding outgoing message")
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
if timeout {
|
|
||||||
c.log.Info("timing out submission due to special localpart")
|
|
||||||
mox.Sleep(mox.Context, time.Hour)
|
|
||||||
xsmtpServerErrorf(codes{smtp.C451LocalErr, smtp.SeSys3Other0}, "timing out submission due to special localpart")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
xmsgPrefix := append([]byte(recvHdrFor(rcptAcc.rcptTo.String())), msgPrefix...)
|
||||||
// We always deliver through the queue. It would be more efficient to deliver
|
// todo: don't convert the headers to a body? it seems the body part is optional. does this have consequences for us in other places? ../rfc/5322:343
|
||||||
// directly, but we don't want to circumvent all the anti-spam measures. Accounts
|
if !msgWriter.HaveHeaders {
|
||||||
// on a single mox instance should be allowed to block each other.
|
xmsgPrefix = append(xmsgPrefix, "\r\n"...)
|
||||||
|
|
||||||
for i, rcptAcc := range c.recipients {
|
|
||||||
xmsgPrefix := append([]byte(recvHdrFor(rcptAcc.rcptTo.String())), msgPrefix...)
|
|
||||||
// todo: don't convert the headers to a body? it seems the body part is optional. does this have consequences for us in other places? ../rfc/5322:343
|
|
||||||
if !msgWriter.HaveHeaders {
|
|
||||||
xmsgPrefix = append(xmsgPrefix, "\r\n"...)
|
|
||||||
}
|
|
||||||
|
|
||||||
msgSize := int64(len(xmsgPrefix)) + msgWriter.Size
|
|
||||||
if _, err := queue.Add(ctx, c.log, c.account.Name, *c.mailFrom, rcptAcc.rcptTo, msgWriter.Has8bit, c.smtputf8, msgSize, messageID, xmsgPrefix, dataFile, nil, i == len(c.recipients)-1); err != nil {
|
|
||||||
// Aborting the transaction is not great. But continuing and generating DSNs will
|
|
||||||
// probably result in errors as well...
|
|
||||||
metricSubmission.WithLabelValues("queueerror").Inc()
|
|
||||||
c.log.Errorx("queuing message", err)
|
|
||||||
xsmtpServerErrorf(errCodes(smtp.C451LocalErr, smtp.SeSys3Other0, err), "error delivering message: %v", err)
|
|
||||||
}
|
|
||||||
metricSubmission.WithLabelValues("ok").Inc()
|
|
||||||
c.log.Info("message queued for delivery", mlog.Field("mailfrom", *c.mailFrom), mlog.Field("rcptto", rcptAcc.rcptTo), mlog.Field("smtputf8", c.smtputf8), mlog.Field("msgsize", msgSize))
|
|
||||||
|
|
||||||
err := c.account.DB.Insert(ctx, &store.Outgoing{Recipient: rcptAcc.rcptTo.XString(true)})
|
|
||||||
xcheckf(err, "adding outgoing message")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
msgSize := int64(len(xmsgPrefix)) + msgWriter.Size
|
||||||
|
if _, err := queue.Add(ctx, c.log, c.account.Name, *c.mailFrom, rcptAcc.rcptTo, msgWriter.Has8bit, c.smtputf8, msgSize, messageID, xmsgPrefix, dataFile, nil, i == len(c.recipients)-1); err != nil {
|
||||||
|
// Aborting the transaction is not great. But continuing and generating DSNs will
|
||||||
|
// probably result in errors as well...
|
||||||
|
metricSubmission.WithLabelValues("queueerror").Inc()
|
||||||
|
c.log.Errorx("queuing message", err)
|
||||||
|
xsmtpServerErrorf(errCodes(smtp.C451LocalErr, smtp.SeSys3Other0, err), "error delivering message: %v", err)
|
||||||
|
}
|
||||||
|
metricSubmission.WithLabelValues("ok").Inc()
|
||||||
|
c.log.Info("message queued for delivery", mlog.Field("mailfrom", *c.mailFrom), mlog.Field("rcptto", rcptAcc.rcptTo), mlog.Field("smtputf8", c.smtputf8), mlog.Field("msgsize", msgSize))
|
||||||
|
|
||||||
|
err := c.account.DB.Insert(ctx, &store.Outgoing{Recipient: rcptAcc.rcptTo.XString(true)})
|
||||||
|
xcheckf(err, "adding outgoing message")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = dataFile.Close()
|
err = dataFile.Close()
|
||||||
c.log.Check(err, "closing file after submission")
|
c.log.Check(err, "closing file after submission")
|
||||||
*pdataFile = nil
|
*pdataFile = nil
|
||||||
|
@ -2472,25 +2413,24 @@ func (c *conn) deliver(ctx context.Context, recvHdrFor func(string) string, msgW
|
||||||
metricDelivery.WithLabelValues("delivererror", "localserve").Inc()
|
metricDelivery.WithLabelValues("delivererror", "localserve").Inc()
|
||||||
addError(rcptAcc, code, smtp.SeOther00, false, fmt.Sprintf("failure with code %d due to special localpart", code))
|
addError(rcptAcc, code, smtp.SeOther00, false, fmt.Sprintf("failure with code %d due to special localpart", code))
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
acc.WithWLock(func() {
|
|
||||||
if err := acc.DeliverMailbox(log, a.mailbox, m, dataFile, false); err != nil {
|
|
||||||
log.Errorx("delivering", err)
|
|
||||||
metricDelivery.WithLabelValues("delivererror", a.reason).Inc()
|
|
||||||
addError(rcptAcc, smtp.C451LocalErr, smtp.SeSys3Other0, false, "error processing")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
metricDelivery.WithLabelValues("delivered", a.reason).Inc()
|
|
||||||
log.Info("incoming message delivered", mlog.Field("reason", a.reason), mlog.Field("msgfrom", msgFrom))
|
|
||||||
|
|
||||||
conf, _ := acc.Conf()
|
|
||||||
if conf.RejectsMailbox != "" && messageID != "" {
|
|
||||||
if err := acc.RejectsRemove(log, conf.RejectsMailbox, messageID); err != nil {
|
|
||||||
log.Errorx("removing message from rejects mailbox", err, mlog.Field("messageid", messageID))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
acc.WithWLock(func() {
|
||||||
|
if err := acc.DeliverMailbox(log, a.mailbox, m, dataFile, false); err != nil {
|
||||||
|
log.Errorx("delivering", err)
|
||||||
|
metricDelivery.WithLabelValues("delivererror", a.reason).Inc()
|
||||||
|
addError(rcptAcc, smtp.C451LocalErr, smtp.SeSys3Other0, false, "error processing")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
metricDelivery.WithLabelValues("delivered", a.reason).Inc()
|
||||||
|
log.Info("incoming message delivered", mlog.Field("reason", a.reason), mlog.Field("msgfrom", msgFrom))
|
||||||
|
|
||||||
|
conf, _ := acc.Conf()
|
||||||
|
if conf.RejectsMailbox != "" && messageID != "" {
|
||||||
|
if err := acc.RejectsRemove(log, conf.RejectsMailbox, messageID); err != nil {
|
||||||
|
log.Errorx("removing message from rejects mailbox", err, mlog.Field("messageid", messageID))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
err = acc.Close()
|
err = acc.Close()
|
||||||
log.Check(err, "closing account after delivering")
|
log.Check(err, "closing account after delivering")
|
||||||
|
|
Loading…
Reference in a new issue