mirror of
https://github.com/mjl-/mox.git
synced 2025-07-12 17:44:35 +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:
@ -649,7 +649,7 @@ func (Account) FromIDLoginAddressesSave(ctx context.Context, loginAddresses []st
|
||||
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) {
|
||||
reqInfo := ctx.Value(requestInfoCtxKey).(requestInfo)
|
||||
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")
|
||||
}
|
||||
|
||||
// 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];
|
||||
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) {
|
||||
const fn = "KeepRetiredPeriodsSave";
|
||||
const paramTypes = [["int64"], ["int64"]];
|
||||
@ -489,6 +489,23 @@ var api;
|
||||
const params = [keepRetiredMessagePeriod, keepRetiredWebhookPeriod];
|
||||
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.defaultBaseURL = (function () {
|
||||
@ -1063,6 +1080,14 @@ const index = async () => {
|
||||
let password1;
|
||||
let password2;
|
||||
let passwordHint;
|
||||
let autoJunkFlagsFieldset;
|
||||
let autoJunkFlagsEnabled;
|
||||
let junkMailboxRegexp;
|
||||
let neutralMailboxRegexp;
|
||||
let notJunkMailboxRegexp;
|
||||
let rejectsFieldset;
|
||||
let rejectsMailbox;
|
||||
let keepRejects;
|
||||
let outgoingWebhookFieldset;
|
||||
let outgoingWebhookURL;
|
||||
let outgoingWebhookAuthorization;
|
||||
@ -1381,7 +1406,15 @@ const index = async () => {
|
||||
' (',
|
||||
'' + 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.stopPropagation();
|
||||
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 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 outgoingWebhookURL: HTMLInputElement
|
||||
let outgoingWebhookAuthorization: HTMLInputElement
|
||||
@ -829,6 +839,65 @@ const index = async () => {
|
||||
'%).',
|
||||
] : [', 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.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(
|
||||
|
@ -438,6 +438,13 @@ func TestAccount(t *testing.T) {
|
||||
api.KeepRetiredPeriodsSave(ctx, time.Minute, time.Minute)
|
||||
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)
|
||||
tneedErrorCode(t, "server:error", func() { api.Logout(ctx) })
|
||||
}
|
||||
|
@ -370,7 +370,7 @@
|
||||
},
|
||||
{
|
||||
"Name": "KeepRetiredPeriodsSave",
|
||||
"Docs": "KeepRetiredPeriodsSave save periods to save retired messages and webhooks.",
|
||||
"Docs": "KeepRetiredPeriodsSave saves periods to save retired messages and webhooks.",
|
||||
"Params": [
|
||||
{
|
||||
"Name": "keepRetiredMessagePeriod",
|
||||
@ -386,6 +386,56 @@
|
||||
}
|
||||
],
|
||||
"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": [],
|
||||
|
@ -451,7 +451,7 @@ export class Client {
|
||||
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> {
|
||||
const fn: string = "KeepRetiredPeriodsSave"
|
||||
const paramTypes: string[][] = [["int64"],["int64"]]
|
||||
@ -459,6 +459,25 @@ export class Client {
|
||||
const params: any[] = [keepRetiredMessagePeriod, keepRetiredWebhookPeriod]
|
||||
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() {
|
||||
|
Reference in New Issue
Block a user