mirror of
https://github.com/mjl-/mox.git
synced 2024-12-26 16:33:47 +03:00
make more account config fields configurable through web interface
so users can change it themselves, instead of requiring an admin to change the settings.
This commit is contained in:
parent
8bcce40c55
commit
baf4df55a6
8 changed files with 223 additions and 13 deletions
|
@ -376,7 +376,7 @@ type SubjectPass struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type AutomaticJunkFlags struct {
|
type AutomaticJunkFlags struct {
|
||||||
Enabled bool `sconf-doc:"If enabled, flags will be set automatically if they match a regular expression below. When two of the three mailbox regular expressions are set, the remaining one will match all unmatched messages. Messages are matched in the order specified and the search stops on the first match. Mailboxes are lowercased before matching."`
|
Enabled bool `sconf-doc:"If enabled, junk/nonjunk flags will be set automatically if they match some of the regular expressions. When two of the three mailbox regular expressions are set, the remaining one will match all unmatched messages. Messages are matched in the order 'junk', 'neutral', 'not junk', and the search stops on the first match. Mailboxes are lowercased before matching."`
|
||||||
JunkMailboxRegexp string `sconf:"optional" sconf-doc:"Example: ^(junk|spam)."`
|
JunkMailboxRegexp string `sconf:"optional" sconf-doc:"Example: ^(junk|spam)."`
|
||||||
NeutralMailboxRegexp string `sconf:"optional" sconf-doc:"Example: ^(inbox|neutral|postmaster|dmarc|tlsrpt|rejects), and you may wish to add trash depending on how you use it, or leave this empty."`
|
NeutralMailboxRegexp string `sconf:"optional" sconf-doc:"Example: ^(inbox|neutral|postmaster|dmarc|tlsrpt|rejects), and you may wish to add trash depending on how you use it, or leave this empty."`
|
||||||
NotJunkMailboxRegexp string `sconf:"optional" sconf-doc:"Example: .* or an empty string."`
|
NotJunkMailboxRegexp string `sconf:"optional" sconf-doc:"Example: .* or an empty string."`
|
||||||
|
@ -396,7 +396,7 @@ type Account struct {
|
||||||
SubjectPass SubjectPass `sconf:"optional" sconf-doc:"If configured, messages classified as weakly spam are rejected with instructions to retry delivery, but this time with a signed token added to the subject. During the next delivery attempt, the signed token will bypass the spam filter. Messages with a clear spam signal, such as a known bad reputation, are rejected/delayed without a signed token."`
|
SubjectPass SubjectPass `sconf:"optional" sconf-doc:"If configured, messages classified as weakly spam are rejected with instructions to retry delivery, but this time with a signed token added to the subject. During the next delivery attempt, the signed token will bypass the spam filter. Messages with a clear spam signal, such as a known bad reputation, are rejected/delayed without a signed token."`
|
||||||
QuotaMessageSize int64 `sconf:"optional" sconf-doc:"Default maximum total message size in bytes for the account, overriding any globally configured default maximum size if non-zero. A negative value can be used to have no limit in case there is a limit by default. Attempting to add new messages to an account beyond its maximum total size will result in an error. Useful to prevent a single account from filling storage."`
|
QuotaMessageSize int64 `sconf:"optional" sconf-doc:"Default maximum total message size in bytes for the account, overriding any globally configured default maximum size if non-zero. A negative value can be used to have no limit in case there is a limit by default. Attempting to add new messages to an account beyond its maximum total size will result in an error. Useful to prevent a single account from filling storage."`
|
||||||
RejectsMailbox string `sconf:"optional" sconf-doc:"Mail that looks like spam will be rejected, but a copy can be stored temporarily in a mailbox, e.g. Rejects. If mail isn't coming in when you expect, you can look there. The mail still isn't accepted, so the remote mail server may retry (hopefully, if legitimate), or give up (hopefully, if indeed a spammer). Messages are automatically removed from this mailbox, so do not set it to a mailbox that has messages you want to keep."`
|
RejectsMailbox string `sconf:"optional" sconf-doc:"Mail that looks like spam will be rejected, but a copy can be stored temporarily in a mailbox, e.g. Rejects. If mail isn't coming in when you expect, you can look there. The mail still isn't accepted, so the remote mail server may retry (hopefully, if legitimate), or give up (hopefully, if indeed a spammer). Messages are automatically removed from this mailbox, so do not set it to a mailbox that has messages you want to keep."`
|
||||||
KeepRejects bool `sconf:"optional" sconf-doc:"Don't automatically delete mail in the RejectsMailbox listed above. This can be useful, e.g. for future spam training."`
|
KeepRejects bool `sconf:"optional" sconf-doc:"Don't automatically delete mail in the RejectsMailbox listed above. This can be useful, e.g. for future spam training. It can also cause storage to fill up."`
|
||||||
AutomaticJunkFlags AutomaticJunkFlags `sconf:"optional" sconf-doc:"Automatically set $Junk and $NotJunk flags based on mailbox messages are delivered/moved/copied to. Email clients typically have too limited functionality to conveniently set these flags, especially $NonJunk, but they can all move messages to a different mailbox, so this helps them."`
|
AutomaticJunkFlags AutomaticJunkFlags `sconf:"optional" sconf-doc:"Automatically set $Junk and $NotJunk flags based on mailbox messages are delivered/moved/copied to. Email clients typically have too limited functionality to conveniently set these flags, especially $NonJunk, but they can all move messages to a different mailbox, so this helps them."`
|
||||||
JunkFilter *JunkFilter `sconf:"optional" sconf-doc:"Content-based filtering, using the junk-status of individual messages to rank words in such messages as spam or ham. It is recommended you always set the applicable (non)-junk status on messages, and that you do not empty your Trash because those messages contain valuable ham/spam training information."` // todo: sane defaults for junkfilter
|
JunkFilter *JunkFilter `sconf:"optional" sconf-doc:"Content-based filtering, using the junk-status of individual messages to rank words in such messages as spam or ham. It is recommended you always set the applicable (non)-junk status on messages, and that you do not empty your Trash because those messages contain valuable ham/spam training information."` // todo: sane defaults for junkfilter
|
||||||
MaxOutgoingMessagesPerDay int `sconf:"optional" sconf-doc:"Maximum number of outgoing messages for this account in a 24 hour window. This limits the damage to recipients and the reputation of this mail server in case of account compromise. Default 1000."`
|
MaxOutgoingMessagesPerDay int `sconf:"optional" sconf-doc:"Maximum number of outgoing messages for this account in a 24 hour window. This limits the damage to recipients and the reputation of this mail server in case of account compromise. Default 1000."`
|
||||||
|
|
|
@ -1046,7 +1046,8 @@ See https://pkg.go.dev/github.com/mjl-/sconf for details.
|
||||||
RejectsMailbox:
|
RejectsMailbox:
|
||||||
|
|
||||||
# Don't automatically delete mail in the RejectsMailbox listed above. This can be
|
# Don't automatically delete mail in the RejectsMailbox listed above. This can be
|
||||||
# useful, e.g. for future spam training. (optional)
|
# useful, e.g. for future spam training. It can also cause storage to fill up.
|
||||||
|
# (optional)
|
||||||
KeepRejects: false
|
KeepRejects: false
|
||||||
|
|
||||||
# Automatically set $Junk and $NotJunk flags based on mailbox messages are
|
# Automatically set $Junk and $NotJunk flags based on mailbox messages are
|
||||||
|
@ -1055,11 +1056,11 @@ See https://pkg.go.dev/github.com/mjl-/sconf for details.
|
||||||
# all move messages to a different mailbox, so this helps them. (optional)
|
# all move messages to a different mailbox, so this helps them. (optional)
|
||||||
AutomaticJunkFlags:
|
AutomaticJunkFlags:
|
||||||
|
|
||||||
# If enabled, flags will be set automatically if they match a regular expression
|
# If enabled, junk/nonjunk flags will be set automatically if they match some of
|
||||||
# below. When two of the three mailbox regular expressions are set, the remaining
|
# the regular expressions. When two of the three mailbox regular expressions are
|
||||||
# one will match all unmatched messages. Messages are matched in the order
|
# set, the remaining one will match all unmatched messages. Messages are matched
|
||||||
# specified and the search stops on the first match. Mailboxes are lowercased
|
# in the order 'junk', 'neutral', 'not junk', and the search stops on the first
|
||||||
# before matching.
|
# match. Mailboxes are lowercased before matching.
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Example: ^(junk|spam). (optional)
|
# Example: ^(junk|spam). (optional)
|
||||||
|
|
|
@ -649,7 +649,7 @@ func (Account) FromIDLoginAddressesSave(ctx context.Context, loginAddresses []st
|
||||||
xcheckf(ctx, err, "saving account fromid login addresses")
|
xcheckf(ctx, err, "saving account fromid login addresses")
|
||||||
}
|
}
|
||||||
|
|
||||||
// KeepRetiredPeriodsSave save periods to save retired messages and webhooks.
|
// KeepRetiredPeriodsSave saves periods to save retired messages and webhooks.
|
||||||
func (Account) KeepRetiredPeriodsSave(ctx context.Context, keepRetiredMessagePeriod, keepRetiredWebhookPeriod time.Duration) {
|
func (Account) KeepRetiredPeriodsSave(ctx context.Context, keepRetiredMessagePeriod, keepRetiredWebhookPeriod time.Duration) {
|
||||||
reqInfo := ctx.Value(requestInfoCtxKey).(requestInfo)
|
reqInfo := ctx.Value(requestInfoCtxKey).(requestInfo)
|
||||||
err := mox.AccountSave(ctx, reqInfo.AccountName, func(acc *config.Account) {
|
err := mox.AccountSave(ctx, reqInfo.AccountName, func(acc *config.Account) {
|
||||||
|
@ -661,3 +661,34 @@ func (Account) KeepRetiredPeriodsSave(ctx context.Context, keepRetiredMessagePer
|
||||||
}
|
}
|
||||||
xcheckf(ctx, err, "saving account keep retired periods")
|
xcheckf(ctx, err, "saving account keep retired periods")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AutomaticJunkFlagsSave saves settings for automatically marking messages as
|
||||||
|
// junk/nonjunk when moved to mailboxes matching certain regular expressions.
|
||||||
|
func (Account) AutomaticJunkFlagsSave(ctx context.Context, enabled bool, junkRegexp, neutralRegexp, notJunkRegexp string) {
|
||||||
|
reqInfo := ctx.Value(requestInfoCtxKey).(requestInfo)
|
||||||
|
err := mox.AccountSave(ctx, reqInfo.AccountName, func(acc *config.Account) {
|
||||||
|
acc.AutomaticJunkFlags = config.AutomaticJunkFlags{
|
||||||
|
Enabled: enabled,
|
||||||
|
JunkMailboxRegexp: junkRegexp,
|
||||||
|
NeutralMailboxRegexp: neutralRegexp,
|
||||||
|
NotJunkMailboxRegexp: notJunkRegexp,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if err != nil && errors.Is(err, mox.ErrConfig) {
|
||||||
|
xcheckuserf(ctx, err, "saving account automatic junk flags")
|
||||||
|
}
|
||||||
|
xcheckf(ctx, err, "saving account automatic junk flags")
|
||||||
|
}
|
||||||
|
|
||||||
|
// RejectsSave saves the RejectsMailbox and KeepRejects settings.
|
||||||
|
func (Account) RejectsSave(ctx context.Context, mailbox string, keep bool) {
|
||||||
|
reqInfo := ctx.Value(requestInfoCtxKey).(requestInfo)
|
||||||
|
err := mox.AccountSave(ctx, reqInfo.AccountName, func(acc *config.Account) {
|
||||||
|
acc.RejectsMailbox = mailbox
|
||||||
|
acc.KeepRejects = keep
|
||||||
|
})
|
||||||
|
if err != nil && errors.Is(err, mox.ErrConfig) {
|
||||||
|
xcheckuserf(ctx, err, "saving account rejects settings")
|
||||||
|
}
|
||||||
|
xcheckf(ctx, err, "saving account rejects settings")
|
||||||
|
}
|
||||||
|
|
|
@ -481,7 +481,7 @@ var api;
|
||||||
const params = [loginAddresses];
|
const params = [loginAddresses];
|
||||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params);
|
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params);
|
||||||
}
|
}
|
||||||
// KeepRetiredPeriodsSave save periods to save retired messages and webhooks.
|
// KeepRetiredPeriodsSave saves periods to save retired messages and webhooks.
|
||||||
async KeepRetiredPeriodsSave(keepRetiredMessagePeriod, keepRetiredWebhookPeriod) {
|
async KeepRetiredPeriodsSave(keepRetiredMessagePeriod, keepRetiredWebhookPeriod) {
|
||||||
const fn = "KeepRetiredPeriodsSave";
|
const fn = "KeepRetiredPeriodsSave";
|
||||||
const paramTypes = [["int64"], ["int64"]];
|
const paramTypes = [["int64"], ["int64"]];
|
||||||
|
@ -489,6 +489,23 @@ var api;
|
||||||
const params = [keepRetiredMessagePeriod, keepRetiredWebhookPeriod];
|
const params = [keepRetiredMessagePeriod, keepRetiredWebhookPeriod];
|
||||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params);
|
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params);
|
||||||
}
|
}
|
||||||
|
// AutomaticJunkFlagsSave saves settings for automatically marking messages as
|
||||||
|
// junk/nonjunk when moved to mailboxes matching certain regular expressions.
|
||||||
|
async AutomaticJunkFlagsSave(enabled, junkRegexp, neutralRegexp, notJunkRegexp) {
|
||||||
|
const fn = "AutomaticJunkFlagsSave";
|
||||||
|
const paramTypes = [["bool"], ["string"], ["string"], ["string"]];
|
||||||
|
const returnTypes = [];
|
||||||
|
const params = [enabled, junkRegexp, neutralRegexp, notJunkRegexp];
|
||||||
|
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params);
|
||||||
|
}
|
||||||
|
// RejectsSave saves the RejectsMailbox and KeepRejects settings.
|
||||||
|
async RejectsSave(mailbox, keep) {
|
||||||
|
const fn = "RejectsSave";
|
||||||
|
const paramTypes = [["string"], ["bool"]];
|
||||||
|
const returnTypes = [];
|
||||||
|
const params = [mailbox, keep];
|
||||||
|
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
api.Client = Client;
|
api.Client = Client;
|
||||||
api.defaultBaseURL = (function () {
|
api.defaultBaseURL = (function () {
|
||||||
|
@ -1063,6 +1080,14 @@ const index = async () => {
|
||||||
let password1;
|
let password1;
|
||||||
let password2;
|
let password2;
|
||||||
let passwordHint;
|
let passwordHint;
|
||||||
|
let autoJunkFlagsFieldset;
|
||||||
|
let autoJunkFlagsEnabled;
|
||||||
|
let junkMailboxRegexp;
|
||||||
|
let neutralMailboxRegexp;
|
||||||
|
let notJunkMailboxRegexp;
|
||||||
|
let rejectsFieldset;
|
||||||
|
let rejectsMailbox;
|
||||||
|
let keepRejects;
|
||||||
let outgoingWebhookFieldset;
|
let outgoingWebhookFieldset;
|
||||||
let outgoingWebhookURL;
|
let outgoingWebhookURL;
|
||||||
let outgoingWebhookAuthorization;
|
let outgoingWebhookAuthorization;
|
||||||
|
@ -1381,7 +1406,15 @@ const index = async () => {
|
||||||
' (',
|
' (',
|
||||||
'' + Math.floor(100 * storageUsed / storageLimit),
|
'' + Math.floor(100 * storageUsed / storageLimit),
|
||||||
'%).',
|
'%).',
|
||||||
] : [', no explicit limit is configured.']), dom.h2('Webhooks'), dom.h3('Outgoing', attr.title('Webhooks for outgoing messages are called for each attempt to deliver a message in the outgoing queue, e.g. when the queue has delivered a message to the next hop, when a single attempt failed with a temporary error, when delivery permanently failed, or when DSN (delivery status notification) messages were received about a previously sent message.')), dom.form(async function submit(e) {
|
] : [', no explicit limit is configured.']), dom.h2('Automatic junk flags', attr.title('For the junk filter to work properly, it needs to be trained: Messages need to be marked as junk or nonjunk. Not all email clients help you set those flags. Automatic junk flags set the junk or nonjunk flags when messages are moved/copied to mailboxes matching configured regular expressions.')), dom.form(async function submit(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
await check(autoJunkFlagsFieldset, client.AutomaticJunkFlagsSave(autoJunkFlagsEnabled.checked, junkMailboxRegexp.value, neutralMailboxRegexp.value, notJunkMailboxRegexp.value));
|
||||||
|
}, autoJunkFlagsFieldset = dom.fieldset(dom.div(style({ display: 'flex', gap: '1em' }), dom.label('Enabled', attr.title("If enabled, junk/nonjunk flags will be set automatically if they match a regular expression below. When two of the three mailbox regular expressions are set, the remaining one will match all unmatched messages. Messages are matched in order 'junk', 'neutral', 'not junk', and the search stops on the first match. Mailboxes are lowercased before matching."), dom.div(autoJunkFlagsEnabled = dom.input(attr.type('checkbox'), acc.AutomaticJunkFlags.Enabled ? attr.checked('') : []))), dom.label('Junk mailbox regexp', dom.div(junkMailboxRegexp = dom.input(attr.value(acc.AutomaticJunkFlags.JunkMailboxRegexp)))), dom.label('Neutral mailbox regexp', dom.div(neutralMailboxRegexp = dom.input(attr.value(acc.AutomaticJunkFlags.NeutralMailboxRegexp)))), dom.label('Not Junk mailbox regexp', dom.div(notJunkMailboxRegexp = dom.input(attr.value(acc.AutomaticJunkFlags.NotJunkMailboxRegexp)))), dom.div(dom.span('\u00a0'), dom.div(dom.submitbutton('Save')))))), dom.br(), dom.h2('Rejects'), dom.form(async function submit(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
await check(rejectsFieldset, client.RejectsSave(rejectsMailbox.value, keepRejects.checked));
|
||||||
|
}, rejectsFieldset = dom.fieldset(dom.div(style({ display: 'flex', gap: '1em' }), dom.label('Mailbox', attr.title("Mail that looks like spam will be rejected, but a copy can be stored temporarily in a mailbox, e.g. Rejects. If mail isn't coming in when you expect, you can look there. The mail still isn't accepted, so the remote mail server may retry (hopefully, if legitimate), or give up (hopefully, if indeed a spammer). Messages are automatically removed from this mailbox, so do not set it to a mailbox that has messages you want to keep."), dom.div(rejectsMailbox = dom.input(attr.value(acc.RejectsMailbox)))), dom.label("No cleanup", attr.title("Don't automatically delete mail in the RejectsMailbox listed above. This can be useful, e.g. for future spam training. It can also cause storage to fill up."), dom.div(keepRejects = dom.input(attr.type('checkbox'), acc.KeepRejects ? attr.checked('') : []))), dom.div(dom.span('\u00a0'), dom.div(dom.submitbutton('Save')))))), dom.br(), dom.h2('Webhooks'), dom.h3('Outgoing', attr.title('Webhooks for outgoing messages are called for each attempt to deliver a message in the outgoing queue, e.g. when the queue has delivered a message to the next hop, when a single attempt failed with a temporary error, when delivery permanently failed, or when DSN (delivery status notification) messages were received about a previously sent message.')), dom.form(async function submit(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
await check(outgoingWebhookFieldset, client.OutgoingWebhookSave(outgoingWebhookURL.value, outgoingWebhookAuthorization.value, [...outgoingWebhookEvents.selectedOptions].map(o => o.value)));
|
await check(outgoingWebhookFieldset, client.OutgoingWebhookSave(outgoingWebhookURL.value, outgoingWebhookAuthorization.value, [...outgoingWebhookEvents.selectedOptions].map(o => o.value)));
|
||||||
|
|
|
@ -302,6 +302,16 @@ const index = async () => {
|
||||||
let password2: HTMLInputElement
|
let password2: HTMLInputElement
|
||||||
let passwordHint: HTMLElement
|
let passwordHint: HTMLElement
|
||||||
|
|
||||||
|
let autoJunkFlagsFieldset: HTMLFieldSetElement
|
||||||
|
let autoJunkFlagsEnabled: HTMLInputElement
|
||||||
|
let junkMailboxRegexp: HTMLInputElement
|
||||||
|
let neutralMailboxRegexp: HTMLInputElement
|
||||||
|
let notJunkMailboxRegexp: HTMLInputElement
|
||||||
|
|
||||||
|
let rejectsFieldset: HTMLFieldSetElement
|
||||||
|
let rejectsMailbox: HTMLInputElement
|
||||||
|
let keepRejects: HTMLInputElement
|
||||||
|
|
||||||
let outgoingWebhookFieldset: HTMLFieldSetElement
|
let outgoingWebhookFieldset: HTMLFieldSetElement
|
||||||
let outgoingWebhookURL: HTMLInputElement
|
let outgoingWebhookURL: HTMLInputElement
|
||||||
let outgoingWebhookAuthorization: HTMLInputElement
|
let outgoingWebhookAuthorization: HTMLInputElement
|
||||||
|
@ -829,6 +839,65 @@ const index = async () => {
|
||||||
'%).',
|
'%).',
|
||||||
] : [', no explicit limit is configured.']),
|
] : [', no explicit limit is configured.']),
|
||||||
|
|
||||||
|
dom.h2('Automatic junk flags', attr.title('For the junk filter to work properly, it needs to be trained: Messages need to be marked as junk or nonjunk. Not all email clients help you set those flags. Automatic junk flags set the junk or nonjunk flags when messages are moved/copied to mailboxes matching configured regular expressions.')),
|
||||||
|
dom.form(
|
||||||
|
async function submit(e: SubmitEvent) {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
|
||||||
|
await check(autoJunkFlagsFieldset, client.AutomaticJunkFlagsSave(autoJunkFlagsEnabled.checked, junkMailboxRegexp.value, neutralMailboxRegexp.value, notJunkMailboxRegexp.value))
|
||||||
|
},
|
||||||
|
autoJunkFlagsFieldset=dom.fieldset(
|
||||||
|
dom.div(style({display: 'flex', gap: '1em'}),
|
||||||
|
dom.label(
|
||||||
|
'Enabled',
|
||||||
|
attr.title("If enabled, junk/nonjunk flags will be set automatically if they match a regular expression below. When two of the three mailbox regular expressions are set, the remaining one will match all unmatched messages. Messages are matched in order 'junk', 'neutral', 'not junk', and the search stops on the first match. Mailboxes are lowercased before matching."),
|
||||||
|
dom.div(autoJunkFlagsEnabled=dom.input(attr.type('checkbox'), acc.AutomaticJunkFlags.Enabled ? attr.checked('') : [])),
|
||||||
|
),
|
||||||
|
dom.label(
|
||||||
|
'Junk mailbox regexp',
|
||||||
|
dom.div(junkMailboxRegexp=dom.input(attr.value(acc.AutomaticJunkFlags.JunkMailboxRegexp))),
|
||||||
|
),
|
||||||
|
dom.label(
|
||||||
|
'Neutral mailbox regexp',
|
||||||
|
dom.div(neutralMailboxRegexp=dom.input(attr.value(acc.AutomaticJunkFlags.NeutralMailboxRegexp))),
|
||||||
|
),
|
||||||
|
dom.label(
|
||||||
|
'Not Junk mailbox regexp',
|
||||||
|
dom.div(notJunkMailboxRegexp=dom.input(attr.value(acc.AutomaticJunkFlags.NotJunkMailboxRegexp))),
|
||||||
|
),
|
||||||
|
dom.div(dom.span('\u00a0'), dom.div(dom.submitbutton('Save'))),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
dom.br(),
|
||||||
|
|
||||||
|
dom.h2('Rejects'),
|
||||||
|
dom.form(
|
||||||
|
async function submit(e: SubmitEvent) {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
|
||||||
|
await check(rejectsFieldset, client.RejectsSave(rejectsMailbox.value, keepRejects.checked))
|
||||||
|
},
|
||||||
|
rejectsFieldset=dom.fieldset(
|
||||||
|
dom.div(style({display: 'flex', gap: '1em'}),
|
||||||
|
dom.label(
|
||||||
|
'Mailbox',
|
||||||
|
attr.title("Mail that looks like spam will be rejected, but a copy can be stored temporarily in a mailbox, e.g. Rejects. If mail isn't coming in when you expect, you can look there. The mail still isn't accepted, so the remote mail server may retry (hopefully, if legitimate), or give up (hopefully, if indeed a spammer). Messages are automatically removed from this mailbox, so do not set it to a mailbox that has messages you want to keep."),
|
||||||
|
dom.div(rejectsMailbox=dom.input(attr.value(acc.RejectsMailbox))),
|
||||||
|
),
|
||||||
|
dom.label(
|
||||||
|
"No cleanup",
|
||||||
|
attr.title("Don't automatically delete mail in the RejectsMailbox listed above. This can be useful, e.g. for future spam training. It can also cause storage to fill up."),
|
||||||
|
dom.div(keepRejects=dom.input(attr.type('checkbox'), acc.KeepRejects ? attr.checked('') : [])),
|
||||||
|
),
|
||||||
|
dom.div(dom.span('\u00a0'), dom.div(dom.submitbutton('Save'))),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
dom.br(),
|
||||||
|
|
||||||
dom.h2('Webhooks'),
|
dom.h2('Webhooks'),
|
||||||
dom.h3('Outgoing', attr.title('Webhooks for outgoing messages are called for each attempt to deliver a message in the outgoing queue, e.g. when the queue has delivered a message to the next hop, when a single attempt failed with a temporary error, when delivery permanently failed, or when DSN (delivery status notification) messages were received about a previously sent message.')),
|
dom.h3('Outgoing', attr.title('Webhooks for outgoing messages are called for each attempt to deliver a message in the outgoing queue, e.g. when the queue has delivered a message to the next hop, when a single attempt failed with a temporary error, when delivery permanently failed, or when DSN (delivery status notification) messages were received about a previously sent message.')),
|
||||||
dom.form(
|
dom.form(
|
||||||
|
|
|
@ -438,6 +438,13 @@ func TestAccount(t *testing.T) {
|
||||||
api.KeepRetiredPeriodsSave(ctx, time.Minute, time.Minute)
|
api.KeepRetiredPeriodsSave(ctx, time.Minute, time.Minute)
|
||||||
api.KeepRetiredPeriodsSave(ctx, 0, 0) // Restore.
|
api.KeepRetiredPeriodsSave(ctx, 0, 0) // Restore.
|
||||||
|
|
||||||
|
api.AutomaticJunkFlagsSave(ctx, true, "^(junk|spam)", "^(inbox|neutral|postmaster|dmarc|tlsrpt|rejects)", "")
|
||||||
|
api.AutomaticJunkFlagsSave(ctx, false, "", "", "")
|
||||||
|
|
||||||
|
api.RejectsSave(ctx, "Rejects", true)
|
||||||
|
api.RejectsSave(ctx, "Rejects", false)
|
||||||
|
api.RejectsSave(ctx, "", false) // Restore.
|
||||||
|
|
||||||
api.Logout(ctx)
|
api.Logout(ctx)
|
||||||
tneedErrorCode(t, "server:error", func() { api.Logout(ctx) })
|
tneedErrorCode(t, "server:error", func() { api.Logout(ctx) })
|
||||||
}
|
}
|
||||||
|
|
|
@ -370,7 +370,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "KeepRetiredPeriodsSave",
|
"Name": "KeepRetiredPeriodsSave",
|
||||||
"Docs": "KeepRetiredPeriodsSave save periods to save retired messages and webhooks.",
|
"Docs": "KeepRetiredPeriodsSave saves periods to save retired messages and webhooks.",
|
||||||
"Params": [
|
"Params": [
|
||||||
{
|
{
|
||||||
"Name": "keepRetiredMessagePeriod",
|
"Name": "keepRetiredMessagePeriod",
|
||||||
|
@ -386,6 +386,56 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Returns": []
|
"Returns": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "AutomaticJunkFlagsSave",
|
||||||
|
"Docs": "AutomaticJunkFlagsSave saves settings for automatically marking messages as\njunk/nonjunk when moved to mailboxes matching certain regular expressions.",
|
||||||
|
"Params": [
|
||||||
|
{
|
||||||
|
"Name": "enabled",
|
||||||
|
"Typewords": [
|
||||||
|
"bool"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "junkRegexp",
|
||||||
|
"Typewords": [
|
||||||
|
"string"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "neutralRegexp",
|
||||||
|
"Typewords": [
|
||||||
|
"string"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "notJunkRegexp",
|
||||||
|
"Typewords": [
|
||||||
|
"string"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Returns": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "RejectsSave",
|
||||||
|
"Docs": "RejectsSave saves the RejectsMailbox and KeepRejects settings.",
|
||||||
|
"Params": [
|
||||||
|
{
|
||||||
|
"Name": "mailbox",
|
||||||
|
"Typewords": [
|
||||||
|
"string"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "keep",
|
||||||
|
"Typewords": [
|
||||||
|
"bool"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Returns": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Sections": [],
|
"Sections": [],
|
||||||
|
|
|
@ -451,7 +451,7 @@ export class Client {
|
||||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
|
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
|
||||||
}
|
}
|
||||||
|
|
||||||
// KeepRetiredPeriodsSave save periods to save retired messages and webhooks.
|
// KeepRetiredPeriodsSave saves periods to save retired messages and webhooks.
|
||||||
async KeepRetiredPeriodsSave(keepRetiredMessagePeriod: number, keepRetiredWebhookPeriod: number): Promise<void> {
|
async KeepRetiredPeriodsSave(keepRetiredMessagePeriod: number, keepRetiredWebhookPeriod: number): Promise<void> {
|
||||||
const fn: string = "KeepRetiredPeriodsSave"
|
const fn: string = "KeepRetiredPeriodsSave"
|
||||||
const paramTypes: string[][] = [["int64"],["int64"]]
|
const paramTypes: string[][] = [["int64"],["int64"]]
|
||||||
|
@ -459,6 +459,25 @@ export class Client {
|
||||||
const params: any[] = [keepRetiredMessagePeriod, keepRetiredWebhookPeriod]
|
const params: any[] = [keepRetiredMessagePeriod, keepRetiredWebhookPeriod]
|
||||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
|
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AutomaticJunkFlagsSave saves settings for automatically marking messages as
|
||||||
|
// junk/nonjunk when moved to mailboxes matching certain regular expressions.
|
||||||
|
async AutomaticJunkFlagsSave(enabled: boolean, junkRegexp: string, neutralRegexp: string, notJunkRegexp: string): Promise<void> {
|
||||||
|
const fn: string = "AutomaticJunkFlagsSave"
|
||||||
|
const paramTypes: string[][] = [["bool"],["string"],["string"],["string"]]
|
||||||
|
const returnTypes: string[][] = []
|
||||||
|
const params: any[] = [enabled, junkRegexp, neutralRegexp, notJunkRegexp]
|
||||||
|
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
|
||||||
|
}
|
||||||
|
|
||||||
|
// RejectsSave saves the RejectsMailbox and KeepRejects settings.
|
||||||
|
async RejectsSave(mailbox: string, keep: boolean): Promise<void> {
|
||||||
|
const fn: string = "RejectsSave"
|
||||||
|
const paramTypes: string[][] = [["string"],["bool"]]
|
||||||
|
const returnTypes: string[][] = []
|
||||||
|
const params: any[] = [mailbox, keep]
|
||||||
|
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultBaseURL = (function() {
|
export const defaultBaseURL = (function() {
|
||||||
|
|
Loading…
Reference in a new issue