mirror of
https://github.com/mjl-/mox.git
synced 2024-12-26 16:33:47 +03:00
remove last remnants of treating a mailbox named "Sent" specially, in favor of special-use mailbox flags
a few places still looked at the name "Sent". but since we have special-use flags, we should always look at those. this also changes the config so admins can specify different names for the special-use mailboxes to create for new accounts, e.g. in a different language. the old config option is still understood, just deprecated.
This commit is contained in:
parent
19b819d222
commit
34ede1075d
12 changed files with 176 additions and 52 deletions
|
@ -57,7 +57,8 @@ type Static struct {
|
||||||
Account string
|
Account string
|
||||||
Mailbox string `sconf-doc:"E.g. Postmaster or Inbox."`
|
Mailbox string `sconf-doc:"E.g. Postmaster or Inbox."`
|
||||||
} `sconf-doc:"Destination for emails delivered to postmaster addresses: a plain 'postmaster' without domain, 'postmaster@<hostname>' (also for each listener with SMTP enabled), and as fallback for each domain without explicitly configured postmaster destination."`
|
} `sconf-doc:"Destination for emails delivered to postmaster addresses: a plain 'postmaster' without domain, 'postmaster@<hostname>' (also for each listener with SMTP enabled), and as fallback for each domain without explicitly configured postmaster destination."`
|
||||||
DefaultMailboxes []string `sconf:"optional" sconf-doc:"Mailboxes to create when adding an account. Inbox is always created. If no mailboxes are specified, the following are automatically created: Sent, Archive, Trash, Drafts and Junk."`
|
InitialMailboxes InitialMailboxes `sconf:"optional" sconf-doc:"Mailboxes to create for new accounts. Inbox is always created. Mailboxes can be given a 'special-use' role, which are understood by most mail clients. If absent/empty, the following mailboxes are created: Sent, Archive, Trash, Drafts and Junk."`
|
||||||
|
DefaultMailboxes []string `sconf:"optional" sconf-doc:"Deprecated in favor of InitialMailboxes. Mailboxes to create when adding an account. Inbox is always created. If no mailboxes are specified, the following are automatically created: Sent, Archive, Trash, Drafts and Junk."`
|
||||||
Transports map[string]Transport `sconf:"optional" sconf-doc:"Transport are mechanisms for delivering messages. Transports can be referenced from Routes in accounts, domains and the global configuration. There is always an implicit/fallback delivery transport doing direct delivery with SMTP from the outgoing message queue. Transports are typically only configured when using smarthosts, i.e. when delivering through another SMTP server. Zero or one transport methods must be set in a transport, never multiple. When using an external party to send email for a domain, keep in mind you may have to add their IP address to your domain's SPF record, and possibly additional DKIM records."`
|
Transports map[string]Transport `sconf:"optional" sconf-doc:"Transport are mechanisms for delivering messages. Transports can be referenced from Routes in accounts, domains and the global configuration. There is always an implicit/fallback delivery transport doing direct delivery with SMTP from the outgoing message queue. Transports are typically only configured when using smarthosts, i.e. when delivering through another SMTP server. Zero or one transport methods must be set in a transport, never multiple. When using an external party to send email for a domain, keep in mind you may have to add their IP address to your domain's SPF record, and possibly additional DKIM records."`
|
||||||
|
|
||||||
// All IPs that were explicitly listen on for external SMTP. Only set when there
|
// All IPs that were explicitly listen on for external SMTP. Only set when there
|
||||||
|
@ -74,6 +75,23 @@ type Static struct {
|
||||||
GID uint32 `sconf:"-" json:"-"`
|
GID uint32 `sconf:"-" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InitialMailboxes are mailboxes created for a new account.
|
||||||
|
type InitialMailboxes struct {
|
||||||
|
SpecialUse SpecialUseMailboxes `sconf:"optional" sconf-doc:"Special-use roles to mailbox to create."`
|
||||||
|
Regular []string `sconf:"optional" sconf-doc:"Regular, non-special-use mailboxes to create."`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SpecialUseMailboxes holds mailbox names for special-use roles. Mail clients
|
||||||
|
// recognize these special-use roles, e.g. appending sent messages to whichever
|
||||||
|
// mailbox has the Sent special-use flag.
|
||||||
|
type SpecialUseMailboxes struct {
|
||||||
|
Sent string `sconf:"optional"`
|
||||||
|
Archive string `sconf:"optional"`
|
||||||
|
Trash string `sconf:"optional"`
|
||||||
|
Draft string `sconf:"optional"`
|
||||||
|
Junk string `sconf:"optional"`
|
||||||
|
}
|
||||||
|
|
||||||
// Dynamic is the parsed form of domains.conf, and is automatically reloaded when changed.
|
// Dynamic is the parsed form of domains.conf, and is automatically reloaded when changed.
|
||||||
type Dynamic struct {
|
type Dynamic struct {
|
||||||
Domains map[string]Domain `sconf-doc:"Domains for which email is accepted. For internationalized domains, use their IDNA names in UTF-8."`
|
Domains map[string]Domain `sconf-doc:"Domains for which email is accepted. For internationalized domains, use their IDNA names in UTF-8."`
|
||||||
|
|
|
@ -359,9 +359,37 @@ describe-static" and "mox config describe-domains":
|
||||||
# E.g. Postmaster or Inbox.
|
# E.g. Postmaster or Inbox.
|
||||||
Mailbox:
|
Mailbox:
|
||||||
|
|
||||||
# Mailboxes to create when adding an account. Inbox is always created. If no
|
# Mailboxes to create for new accounts. Inbox is always created. Mailboxes can be
|
||||||
# mailboxes are specified, the following are automatically created: Sent, Archive,
|
# given a 'special-use' role, which are understood by most mail clients. If
|
||||||
# Trash, Drafts and Junk. (optional)
|
# absent/empty, the following mailboxes are created: Sent, Archive, Trash, Drafts
|
||||||
|
# and Junk. (optional)
|
||||||
|
InitialMailboxes:
|
||||||
|
|
||||||
|
# Special-use roles to mailbox to create. (optional)
|
||||||
|
SpecialUse:
|
||||||
|
|
||||||
|
# (optional)
|
||||||
|
Sent:
|
||||||
|
|
||||||
|
# (optional)
|
||||||
|
Archive:
|
||||||
|
|
||||||
|
# (optional)
|
||||||
|
Trash:
|
||||||
|
|
||||||
|
# (optional)
|
||||||
|
Draft:
|
||||||
|
|
||||||
|
# (optional)
|
||||||
|
Junk:
|
||||||
|
|
||||||
|
# Regular, non-special-use mailboxes to create. (optional)
|
||||||
|
Regular:
|
||||||
|
-
|
||||||
|
|
||||||
|
# Deprecated in favor of InitialMailboxes. Mailboxes to create when adding an
|
||||||
|
# account. Inbox is always created. If no mailboxes are specified, the following
|
||||||
|
# are automatically created: Sent, Archive, Trash, Drafts and Junk. (optional)
|
||||||
DefaultMailboxes:
|
DefaultMailboxes:
|
||||||
-
|
-
|
||||||
|
|
||||||
|
|
12
doc.go
12
doc.go
|
@ -236,9 +236,9 @@ Import a maildir into an account.
|
||||||
By default, messages will train the junk filter based on their flags and, if
|
By default, messages will train the junk filter based on their flags and, if
|
||||||
"automatic junk flags" configuration is set, based on mailbox naming.
|
"automatic junk flags" configuration is set, based on mailbox naming.
|
||||||
|
|
||||||
If the destination mailbox is "Sent", the recipients of the messages are added
|
If the destination mailbox is the Sent mailbox, the recipients of the messages
|
||||||
to the message metadata, causing later incoming messages from these recipients
|
are added to the message metadata, causing later incoming messages from these
|
||||||
to be accepted, unless other reputation signals prevent that.
|
recipients to be accepted, unless other reputation signals prevent that.
|
||||||
|
|
||||||
Users can also import mailboxes/messages through the account web page by
|
Users can also import mailboxes/messages through the account web page by
|
||||||
uploading a zip or tgz file with mbox and/or maildirs.
|
uploading a zip or tgz file with mbox and/or maildirs.
|
||||||
|
@ -260,9 +260,9 @@ Using mbox is not recommended, maildir is a better defined format.
|
||||||
By default, messages will train the junk filter based on their flags and, if
|
By default, messages will train the junk filter based on their flags and, if
|
||||||
"automatic junk flags" configuration is set, based on mailbox naming.
|
"automatic junk flags" configuration is set, based on mailbox naming.
|
||||||
|
|
||||||
If the destination mailbox is "Sent", the recipients of the messages are added
|
If the destination mailbox is the Sent mailbox, the recipients of the messages
|
||||||
to the message metadata, causing later incoming messages from these recipients
|
are added to the message metadata, causing later incoming messages from these
|
||||||
to be accepted, unless other reputation signals prevent that.
|
recipients to be accepted, unless other reputation signals prevent that.
|
||||||
|
|
||||||
Users can also import mailboxes/messages through the account web page by
|
Users can also import mailboxes/messages through the account web page by
|
||||||
uploading a zip or tgz file with mbox and/or maildirs.
|
uploading a zip or tgz file with mbox and/or maildirs.
|
||||||
|
|
|
@ -281,7 +281,7 @@ Accounts:
|
||||||
xcheckf(err, "creating temp file for delivery")
|
xcheckf(err, "creating temp file for delivery")
|
||||||
_, err = fmt.Fprint(mf, msg)
|
_, err = fmt.Fprint(mf, msg)
|
||||||
xcheckf(err, "writing deliver message to file")
|
xcheckf(err, "writing deliver message to file")
|
||||||
err = accTest1.DeliverMessage(log, tx, &m, mf, true, false, false, true)
|
err = accTest1.DeliverMessage(log, tx, &m, mf, true, false, true)
|
||||||
xcheckf(err, "add message to account test1")
|
xcheckf(err, "add message to account test1")
|
||||||
err = mf.Close()
|
err = mf.Close()
|
||||||
xcheckf(err, "closing file")
|
xcheckf(err, "closing file")
|
||||||
|
@ -335,7 +335,7 @@ Accounts:
|
||||||
xcheckf(err, "creating temp file for delivery")
|
xcheckf(err, "creating temp file for delivery")
|
||||||
_, err = fmt.Fprint(mf0, msg0)
|
_, err = fmt.Fprint(mf0, msg0)
|
||||||
xcheckf(err, "writing deliver message to file")
|
xcheckf(err, "writing deliver message to file")
|
||||||
err = accTest2.DeliverMessage(log, tx, &m0, mf0, true, false, false, false)
|
err = accTest2.DeliverMessage(log, tx, &m0, mf0, true, false, false)
|
||||||
xcheckf(err, "add message to account test2")
|
xcheckf(err, "add message to account test2")
|
||||||
err = mf0.Close()
|
err = mf0.Close()
|
||||||
xcheckf(err, "closing file")
|
xcheckf(err, "closing file")
|
||||||
|
@ -362,7 +362,7 @@ Accounts:
|
||||||
xcheckf(err, "creating temp file for delivery")
|
xcheckf(err, "creating temp file for delivery")
|
||||||
_, err = fmt.Fprint(mf1, msg1)
|
_, err = fmt.Fprint(mf1, msg1)
|
||||||
xcheckf(err, "writing deliver message to file")
|
xcheckf(err, "writing deliver message to file")
|
||||||
err = accTest2.DeliverMessage(log, tx, &m1, mf1, true, true, false, false)
|
err = accTest2.DeliverMessage(log, tx, &m1, mf1, true, false, false)
|
||||||
xcheckf(err, "add message to account test2")
|
xcheckf(err, "add message to account test2")
|
||||||
err = mf1.Close()
|
err = mf1.Close()
|
||||||
xcheckf(err, "closing file")
|
xcheckf(err, "closing file")
|
||||||
|
|
|
@ -71,7 +71,11 @@ func TestListExtended(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uidvals := map[string]uint32{}
|
uidvals := map[string]uint32{}
|
||||||
for _, name := range store.InitialMailboxes {
|
use := store.DefaultInitialMailboxes.SpecialUse
|
||||||
|
for _, name := range []string{"Inbox", use.Archive, use.Draft, use.Junk, use.Sent, use.Trash} {
|
||||||
|
uidvals[name] = 1
|
||||||
|
}
|
||||||
|
for _, name := range store.DefaultInitialMailboxes.Regular {
|
||||||
uidvals[name] = 1
|
uidvals[name] = 1
|
||||||
}
|
}
|
||||||
var uidvalnext uint32 = 2
|
var uidvalnext uint32 = 2
|
||||||
|
|
|
@ -2741,8 +2741,7 @@ func (c *conn) cmdAppend(tag, cmd string, p *parser) {
|
||||||
err = tx.Update(&mb)
|
err = tx.Update(&mb)
|
||||||
xcheckf(err, "updating mailbox counts")
|
xcheckf(err, "updating mailbox counts")
|
||||||
|
|
||||||
isSent := name == "Sent"
|
err := c.account.DeliverMessage(c.log, tx, &m, msgFile, true, true, false)
|
||||||
err := c.account.DeliverMessage(c.log, tx, &m, msgFile, true, isSent, true, false)
|
|
||||||
xcheckf(err, "delivering message")
|
xcheckf(err, "delivering message")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -30,9 +30,9 @@ import (
|
||||||
const importCommonHelp = `By default, messages will train the junk filter based on their flags and, if
|
const importCommonHelp = `By default, messages will train the junk filter based on their flags and, if
|
||||||
"automatic junk flags" configuration is set, based on mailbox naming.
|
"automatic junk flags" configuration is set, based on mailbox naming.
|
||||||
|
|
||||||
If the destination mailbox is "Sent", the recipients of the messages are added
|
If the destination mailbox is the Sent mailbox, the recipients of the messages
|
||||||
to the message metadata, causing later incoming messages from these recipients
|
are added to the message metadata, causing later incoming messages from these
|
||||||
to be accepted, unless other reputation signals prevent that.
|
recipients to be accepted, unless other reputation signals prevent that.
|
||||||
|
|
||||||
Users can also import mailboxes/messages through the account web page by
|
Users can also import mailboxes/messages through the account web page by
|
||||||
uploading a zip or tgz file with mbox and/or maildirs.
|
uploading a zip or tgz file with mbox and/or maildirs.
|
||||||
|
@ -275,10 +275,9 @@ func importctl(ctx context.Context, ctl *ctl, mbox bool) {
|
||||||
// todo: possibly set dmarcdomain to the domain of the from address? at least for non-spams that have been seen. otherwise user would start without any reputations. the assumption would be that the user has accepted email and deemed it legit, coming from the indicated sender.
|
// todo: possibly set dmarcdomain to the domain of the from address? at least for non-spams that have been seen. otherwise user would start without any reputations. the assumption would be that the user has accepted email and deemed it legit, coming from the indicated sender.
|
||||||
|
|
||||||
const consumeFile = true
|
const consumeFile = true
|
||||||
isSent := mailbox == "Sent"
|
|
||||||
const sync = false
|
const sync = false
|
||||||
const notrain = true
|
const notrain = true
|
||||||
err := a.DeliverMessage(ctl.log, tx, m, mf, consumeFile, isSent, sync, notrain)
|
err := a.DeliverMessage(ctl.log, tx, m, mf, consumeFile, sync, notrain)
|
||||||
ctl.xcheck(err, "delivering message")
|
ctl.xcheck(err, "delivering message")
|
||||||
deliveredIDs = append(deliveredIDs, m.ID)
|
deliveredIDs = append(deliveredIDs, m.ID)
|
||||||
ctl.log.Debug("delivered message", mlog.Field("id", m.ID))
|
ctl.log.Debug("delivered message", mlog.Field("id", m.ID))
|
||||||
|
|
|
@ -644,9 +644,33 @@ func PrepareStaticConfig(ctx context.Context, configFile string, conf *Config, c
|
||||||
c.SpecifiedSMTPListenIPs = nil
|
c.SpecifiedSMTPListenIPs = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var zerouse config.SpecialUseMailboxes
|
||||||
|
if len(c.DefaultMailboxes) > 0 && (c.InitialMailboxes.SpecialUse != zerouse || len(c.InitialMailboxes.Regular) > 0) {
|
||||||
|
addErrorf("cannot have both DefaultMailboxes and InitialMailboxes")
|
||||||
|
}
|
||||||
|
// DefaultMailboxes is deprecated.
|
||||||
for _, mb := range c.DefaultMailboxes {
|
for _, mb := range c.DefaultMailboxes {
|
||||||
checkMailboxNormf(mb, "default mailbox")
|
checkMailboxNormf(mb, "default mailbox")
|
||||||
}
|
}
|
||||||
|
checkSpecialUseMailbox := func(nameOpt string) {
|
||||||
|
if nameOpt != "" {
|
||||||
|
checkMailboxNormf(nameOpt, "special-use initial mailbox")
|
||||||
|
if strings.EqualFold(nameOpt, "inbox") {
|
||||||
|
addErrorf("initial mailbox cannot be set to Inbox (Inbox is always created)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkSpecialUseMailbox(c.InitialMailboxes.SpecialUse.Archive)
|
||||||
|
checkSpecialUseMailbox(c.InitialMailboxes.SpecialUse.Draft)
|
||||||
|
checkSpecialUseMailbox(c.InitialMailboxes.SpecialUse.Junk)
|
||||||
|
checkSpecialUseMailbox(c.InitialMailboxes.SpecialUse.Sent)
|
||||||
|
checkSpecialUseMailbox(c.InitialMailboxes.SpecialUse.Trash)
|
||||||
|
for _, name := range c.InitialMailboxes.Regular {
|
||||||
|
checkMailboxNormf(name, "regular initial mailbox")
|
||||||
|
if strings.EqualFold(name, "inbox") {
|
||||||
|
addErrorf("initial regular mailbox cannot be set to Inbox (Inbox is always created)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
checkTransportSMTP := func(name string, isTLS bool, t *config.TransportSMTP) {
|
checkTransportSMTP := func(name string, isTLS bool, t *config.TransportSMTP) {
|
||||||
var err error
|
var err error
|
||||||
|
|
106
store/account.go
106
store/account.go
|
@ -73,7 +73,15 @@ var (
|
||||||
|
|
||||||
var subjectpassRand = mox.NewRand()
|
var subjectpassRand = mox.NewRand()
|
||||||
|
|
||||||
var InitialMailboxes = []string{"Inbox", "Sent", "Archive", "Trash", "Drafts", "Junk"}
|
var DefaultInitialMailboxes = config.InitialMailboxes{
|
||||||
|
SpecialUse: config.SpecialUseMailboxes{
|
||||||
|
Sent: "Sent",
|
||||||
|
Archive: "Archive",
|
||||||
|
Trash: "Trash",
|
||||||
|
Draft: "Drafts",
|
||||||
|
Junk: "Junk",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
type SCRAM struct {
|
type SCRAM struct {
|
||||||
Salt []byte
|
Salt []byte
|
||||||
|
@ -714,36 +722,79 @@ func initAccount(db *bstore.DB) error {
|
||||||
return db.Write(context.TODO(), func(tx *bstore.Tx) error {
|
return db.Write(context.TODO(), func(tx *bstore.Tx) error {
|
||||||
uidvalidity := InitialUIDValidity()
|
uidvalidity := InitialUIDValidity()
|
||||||
|
|
||||||
mailboxes := InitialMailboxes
|
if len(mox.Conf.Static.DefaultMailboxes) > 0 {
|
||||||
defaultMailboxes := mox.Conf.Static.DefaultMailboxes
|
// Deprecated in favor of InitialMailboxes.
|
||||||
if len(defaultMailboxes) > 0 {
|
defaultMailboxes := mox.Conf.Static.DefaultMailboxes
|
||||||
mailboxes = []string{"Inbox"}
|
mailboxes := []string{"Inbox"}
|
||||||
for _, name := range defaultMailboxes {
|
for _, name := range defaultMailboxes {
|
||||||
if strings.EqualFold(name, "Inbox") {
|
if strings.EqualFold(name, "Inbox") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
mailboxes = append(mailboxes, name)
|
mailboxes = append(mailboxes, name)
|
||||||
}
|
}
|
||||||
}
|
for _, name := range mailboxes {
|
||||||
for _, name := range mailboxes {
|
mb := Mailbox{Name: name, UIDValidity: uidvalidity, UIDNext: 1, HaveCounts: true}
|
||||||
mb := Mailbox{Name: name, UIDValidity: uidvalidity, UIDNext: 1, HaveCounts: true}
|
if strings.HasPrefix(name, "Archive") {
|
||||||
if strings.HasPrefix(name, "Archive") {
|
mb.Archive = true
|
||||||
mb.Archive = true
|
} else if strings.HasPrefix(name, "Drafts") {
|
||||||
} else if strings.HasPrefix(name, "Drafts") {
|
mb.Draft = true
|
||||||
mb.Draft = true
|
} else if strings.HasPrefix(name, "Junk") {
|
||||||
} else if strings.HasPrefix(name, "Junk") {
|
mb.Junk = true
|
||||||
mb.Junk = true
|
} else if strings.HasPrefix(name, "Sent") {
|
||||||
} else if strings.HasPrefix(name, "Sent") {
|
mb.Sent = true
|
||||||
mb.Sent = true
|
} else if strings.HasPrefix(name, "Trash") {
|
||||||
} else if strings.HasPrefix(name, "Trash") {
|
mb.Trash = true
|
||||||
mb.Trash = true
|
}
|
||||||
|
if err := tx.Insert(&mb); err != nil {
|
||||||
|
return fmt.Errorf("creating mailbox: %w", err)
|
||||||
|
}
|
||||||
|
if err := tx.Insert(&Subscription{name}); err != nil {
|
||||||
|
return fmt.Errorf("adding subscription: %w", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err := tx.Insert(&mb); err != nil {
|
} else {
|
||||||
return fmt.Errorf("creating mailbox: %w", err)
|
mailboxes := mox.Conf.Static.InitialMailboxes
|
||||||
|
var zerouse config.SpecialUseMailboxes
|
||||||
|
if mailboxes.SpecialUse == zerouse && len(mailboxes.Regular) == 0 {
|
||||||
|
mailboxes = DefaultInitialMailboxes
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := tx.Insert(&Subscription{name}); err != nil {
|
add := func(name string, use SpecialUse) error {
|
||||||
return fmt.Errorf("adding subscription: %w", err)
|
mb := Mailbox{Name: name, UIDValidity: uidvalidity, UIDNext: 1, SpecialUse: use, HaveCounts: true}
|
||||||
|
if err := tx.Insert(&mb); err != nil {
|
||||||
|
return fmt.Errorf("creating mailbox: %w", err)
|
||||||
|
}
|
||||||
|
if err := tx.Insert(&Subscription{name}); err != nil {
|
||||||
|
return fmt.Errorf("adding subscription: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
addSpecialOpt := func(nameOpt string, use SpecialUse) error {
|
||||||
|
if nameOpt == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return add(nameOpt, use)
|
||||||
|
}
|
||||||
|
l := []struct {
|
||||||
|
nameOpt string
|
||||||
|
use SpecialUse
|
||||||
|
}{
|
||||||
|
{"Inbox", SpecialUse{}},
|
||||||
|
{mailboxes.SpecialUse.Archive, SpecialUse{Archive: true}},
|
||||||
|
{mailboxes.SpecialUse.Draft, SpecialUse{Draft: true}},
|
||||||
|
{mailboxes.SpecialUse.Junk, SpecialUse{Junk: true}},
|
||||||
|
{mailboxes.SpecialUse.Sent, SpecialUse{Sent: true}},
|
||||||
|
{mailboxes.SpecialUse.Trash, SpecialUse{Trash: true}},
|
||||||
|
}
|
||||||
|
for _, e := range l {
|
||||||
|
if err := addSpecialOpt(e.nameOpt, e.use); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, name := range mailboxes.Regular {
|
||||||
|
if err := add(name, SpecialUse{}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -934,8 +985,9 @@ func (a *Account) WithRLock(fn func()) {
|
||||||
// section. The caller is responsible for adding a header separator to
|
// section. The caller is responsible for adding a header separator to
|
||||||
// msg.MsgPrefix if missing from an incoming message.
|
// msg.MsgPrefix if missing from an incoming message.
|
||||||
//
|
//
|
||||||
// If isSent is true, the message is parsed for its recipients (to/cc/bcc). Their
|
// If the destination mailbox has the Sent special-use flag, the message is parsed
|
||||||
// domains are added to Recipients for use in dmarc reputation.
|
// for its recipients (to/cc/bcc). Their domains are added to Recipients for use in
|
||||||
|
// dmarc reputation.
|
||||||
//
|
//
|
||||||
// If sync is true, the message file and its directory are synced. Should be true
|
// If sync is true, the message file and its directory are synced. Should be true
|
||||||
// for regular mail delivery, but can be false when importing many messages.
|
// for regular mail delivery, but can be false when importing many messages.
|
||||||
|
@ -947,7 +999,7 @@ func (a *Account) WithRLock(fn func()) {
|
||||||
// Caller must broadcast new message.
|
// Caller must broadcast new message.
|
||||||
//
|
//
|
||||||
// Caller must update mailbox counts.
|
// Caller must update mailbox counts.
|
||||||
func (a *Account) DeliverMessage(log *mlog.Log, tx *bstore.Tx, m *Message, msgFile *os.File, consumeFile, isSent, sync, notrain bool) error {
|
func (a *Account) DeliverMessage(log *mlog.Log, tx *bstore.Tx, m *Message, msgFile *os.File, consumeFile, sync, notrain bool) error {
|
||||||
if m.Expunged {
|
if m.Expunged {
|
||||||
return fmt.Errorf("cannot deliver expunged message")
|
return fmt.Errorf("cannot deliver expunged message")
|
||||||
}
|
}
|
||||||
|
@ -999,7 +1051,7 @@ func (a *Account) DeliverMessage(log *mlog.Log, tx *bstore.Tx, m *Message, msgFi
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: perhaps we should match the recipients based on smtp submission and a matching message-id? we now miss the addresses in bcc's. for webmail, we could insert the recipients directly.
|
// todo: perhaps we should match the recipients based on smtp submission and a matching message-id? we now miss the addresses in bcc's. for webmail, we could insert the recipients directly.
|
||||||
if isSent {
|
if mb.Sent {
|
||||||
// Attempt to parse the message for its To/Cc/Bcc headers, which we insert into Recipient.
|
// Attempt to parse the message for its To/Cc/Bcc headers, which we insert into Recipient.
|
||||||
if part == nil {
|
if part == nil {
|
||||||
var p message.Part
|
var p message.Part
|
||||||
|
@ -1405,7 +1457,7 @@ func (a *Account) DeliverMailbox(log *mlog.Log, mailbox string, m *Message, msgF
|
||||||
return fmt.Errorf("updating mailbox for delivery: %w", err)
|
return fmt.Errorf("updating mailbox for delivery: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := a.DeliverMessage(log, tx, m, msgFile, consumeFile, mb.Sent, true, false); err != nil {
|
if err := a.DeliverMessage(log, tx, m, msgFile, consumeFile, true, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,7 @@ func TestMailbox(t *testing.T) {
|
||||||
tcheck(t, err, "sent mailbox")
|
tcheck(t, err, "sent mailbox")
|
||||||
msent.MailboxID = mbsent.ID
|
msent.MailboxID = mbsent.ID
|
||||||
msent.MailboxOrigID = mbsent.ID
|
msent.MailboxOrigID = mbsent.ID
|
||||||
err = acc.DeliverMessage(xlog, tx, &msent, msgFile, false, true, true, false)
|
err = acc.DeliverMessage(xlog, tx, &msent, msgFile, false, true, false)
|
||||||
tcheck(t, err, "deliver message")
|
tcheck(t, err, "deliver message")
|
||||||
|
|
||||||
err = tx.Get(&mbsent)
|
err = tx.Get(&mbsent)
|
||||||
|
@ -90,7 +90,7 @@ func TestMailbox(t *testing.T) {
|
||||||
tcheck(t, err, "insert rejects mailbox")
|
tcheck(t, err, "insert rejects mailbox")
|
||||||
mreject.MailboxID = mbrejects.ID
|
mreject.MailboxID = mbrejects.ID
|
||||||
mreject.MailboxOrigID = mbrejects.ID
|
mreject.MailboxOrigID = mbrejects.ID
|
||||||
err = acc.DeliverMessage(xlog, tx, &mreject, msgFile, false, false, true, false)
|
err = acc.DeliverMessage(xlog, tx, &mreject, msgFile, false, true, false)
|
||||||
tcheck(t, err, "deliver message")
|
tcheck(t, err, "deliver message")
|
||||||
|
|
||||||
err = tx.Get(&mbrejects)
|
err = tx.Get(&mbrejects)
|
||||||
|
|
|
@ -531,7 +531,7 @@ func importMessages(ctx context.Context, log *mlog.Log, token string, acc *store
|
||||||
const consumeFile = true
|
const consumeFile = true
|
||||||
const sync = false
|
const sync = false
|
||||||
const notrain = true
|
const notrain = true
|
||||||
if err := acc.DeliverMessage(log, tx, m, f, consumeFile, mb.Sent, sync, notrain); err != nil {
|
if err := acc.DeliverMessage(log, tx, m, f, consumeFile, sync, notrain); err != nil {
|
||||||
problemf("delivering message %s: %s (continuing)", pos, err)
|
problemf("delivering message %s: %s (continuing)", pos, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -748,7 +748,7 @@ func (w Webmail) MessageSubmit(ctx context.Context, m SubmitMessage) {
|
||||||
err = tx.Update(&sentmb)
|
err = tx.Update(&sentmb)
|
||||||
xcheckf(ctx, err, "updating sent mailbox for counts")
|
xcheckf(ctx, err, "updating sent mailbox for counts")
|
||||||
|
|
||||||
err = acc.DeliverMessage(log, tx, &sentm, dataFile, true, true, true, false)
|
err = acc.DeliverMessage(log, tx, &sentm, dataFile, true, true, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
metricSubmission.WithLabelValues("storesenterror").Inc()
|
metricSubmission.WithLabelValues("storesenterror").Inc()
|
||||||
metricked = true
|
metricked = true
|
||||||
|
|
Loading…
Reference in a new issue