mirror of
https://github.com/mjl-/mox.git
synced 2025-07-12 17:04:39 +03:00
add aliases/lists: when sending to an alias, the message gets delivered to all members
the members must currently all be addresses of local accounts. a message sent to an alias is accepted if at least one of the members accepts it. if no members accepts it (e.g. due to bad reputation of sender), the message is rejected. if a message is submitted to both an alias addresses and to recipients that are members of the alias in an smtp transaction, the message will be delivered to such members only once. the same applies if the address in the message from-header is the address of a member: that member won't receive the message (they sent it). this prevents duplicate messages. aliases have three configuration options: - PostPublic: whether anyone can send through the alias, or only members. members-only lists can be useful inside organizations for internal communication. public lists can be useful for support addresses. - ListMembers: whether members can see the addresses of other members. this can be seen in the account web interface. in the future, we could export this in other ways, so clients can expand the list. - AllowMsgFrom: whether messages can be sent through the alias with the alias address used in the message from-header. the webmail knows it can use that address, and will use it as from-address when replying to a message sent to that address. ideas for the future: - allow external addresses as members. still with some restrictions, such as requiring a valid dkim-signature so delivery has a chance to succeed. will also need configuration of an admin that can receive any bounces. - allow specifying specific members who can sent through the list (instead of all members). for github issue #57 by hmfaysal. also relevant for #99 by naturalethic. thanks to damir & marin from sartura for discussing requirements/features.
This commit is contained in:
@ -1535,7 +1535,7 @@ func (Admin) DomainConfig(ctx context.Context, domain string) config.Domain {
|
||||
}
|
||||
|
||||
// DomainLocalparts returns the encoded localparts and accounts configured in domain.
|
||||
func (Admin) DomainLocalparts(ctx context.Context, domain string) (localpartAccounts map[string]string) {
|
||||
func (Admin) DomainLocalparts(ctx context.Context, domain string) (localpartAccounts map[string]string, localpartAliases map[string]config.Alias) {
|
||||
d, err := dns.ParseDomain(domain)
|
||||
xcheckuserf(ctx, err, "parsing domain")
|
||||
_, ok := mox.Conf.Domain(d)
|
||||
@ -2430,8 +2430,9 @@ func (Admin) AccountRoutesSave(ctx context.Context, accountName string, routes [
|
||||
|
||||
// DomainRoutesSave saves routes for a domain.
|
||||
func (Admin) DomainRoutesSave(ctx context.Context, domainName string, routes []config.Route) {
|
||||
err := mox.DomainSave(ctx, domainName, func(domain *config.Domain) {
|
||||
err := mox.DomainSave(ctx, domainName, func(domain *config.Domain) error {
|
||||
domain.Routes = routes
|
||||
return nil
|
||||
})
|
||||
xcheckf(ctx, err, "saving domain routes")
|
||||
}
|
||||
@ -2446,16 +2447,18 @@ func (Admin) RoutesSave(ctx context.Context, routes []config.Route) {
|
||||
|
||||
// DomainDescriptionSave saves the description for a domain.
|
||||
func (Admin) DomainDescriptionSave(ctx context.Context, domainName, descr string) {
|
||||
err := mox.DomainSave(ctx, domainName, func(domain *config.Domain) {
|
||||
err := mox.DomainSave(ctx, domainName, func(domain *config.Domain) error {
|
||||
domain.Description = descr
|
||||
return nil
|
||||
})
|
||||
xcheckf(ctx, err, "saving domain description")
|
||||
}
|
||||
|
||||
// DomainClientSettingsDomainSave saves the client settings domain for a domain.
|
||||
func (Admin) DomainClientSettingsDomainSave(ctx context.Context, domainName, clientSettingsDomain string) {
|
||||
err := mox.DomainSave(ctx, domainName, func(domain *config.Domain) {
|
||||
err := mox.DomainSave(ctx, domainName, func(domain *config.Domain) error {
|
||||
domain.ClientSettingsDomain = clientSettingsDomain
|
||||
return nil
|
||||
})
|
||||
xcheckf(ctx, err, "saving client settings domain")
|
||||
}
|
||||
@ -2463,9 +2466,10 @@ func (Admin) DomainClientSettingsDomainSave(ctx context.Context, domainName, cli
|
||||
// DomainLocalpartConfigSave saves the localpart catchall and case-sensitive
|
||||
// settings for a domain.
|
||||
func (Admin) DomainLocalpartConfigSave(ctx context.Context, domainName, localpartCatchallSeparator string, localpartCaseSensitive bool) {
|
||||
err := mox.DomainSave(ctx, domainName, func(domain *config.Domain) {
|
||||
err := mox.DomainSave(ctx, domainName, func(domain *config.Domain) error {
|
||||
domain.LocalpartCatchallSeparator = localpartCatchallSeparator
|
||||
domain.LocalpartCaseSensitive = localpartCaseSensitive
|
||||
return nil
|
||||
})
|
||||
xcheckf(ctx, err, "saving localpart settings for domain")
|
||||
}
|
||||
@ -2474,7 +2478,7 @@ func (Admin) DomainLocalpartConfigSave(ctx context.Context, domainName, localpar
|
||||
// configuration for a domain. If localpart is empty, processing reports is
|
||||
// disabled.
|
||||
func (Admin) DomainDMARCAddressSave(ctx context.Context, domainName, localpart, domain, account, mailbox string) {
|
||||
err := mox.DomainSave(ctx, domainName, func(d *config.Domain) {
|
||||
err := mox.DomainSave(ctx, domainName, func(d *config.Domain) error {
|
||||
if localpart == "" {
|
||||
d.DMARC = nil
|
||||
} else {
|
||||
@ -2485,6 +2489,7 @@ func (Admin) DomainDMARCAddressSave(ctx context.Context, domainName, localpart,
|
||||
Mailbox: mailbox,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
xcheckf(ctx, err, "saving dmarc reporting address/settings for domain")
|
||||
}
|
||||
@ -2493,7 +2498,7 @@ func (Admin) DomainDMARCAddressSave(ctx context.Context, domainName, localpart,
|
||||
// configuration for a domain. If localpart is empty, processing reports is
|
||||
// disabled.
|
||||
func (Admin) DomainTLSRPTAddressSave(ctx context.Context, domainName, localpart, domain, account, mailbox string) {
|
||||
err := mox.DomainSave(ctx, domainName, func(d *config.Domain) {
|
||||
err := mox.DomainSave(ctx, domainName, func(d *config.Domain) error {
|
||||
if localpart == "" {
|
||||
d.TLSRPT = nil
|
||||
} else {
|
||||
@ -2504,6 +2509,7 @@ func (Admin) DomainTLSRPTAddressSave(ctx context.Context, domainName, localpart,
|
||||
Mailbox: mailbox,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
xcheckf(ctx, err, "saving tls reporting address/settings for domain")
|
||||
}
|
||||
@ -2511,7 +2517,7 @@ func (Admin) DomainTLSRPTAddressSave(ctx context.Context, domainName, localpart,
|
||||
// DomainMTASTSSave saves the MTASTS policy for a domain. If policyID is empty,
|
||||
// no MTASTS policy is served.
|
||||
func (Admin) DomainMTASTSSave(ctx context.Context, domainName, policyID string, mode mtasts.Mode, maxAge time.Duration, mx []string) {
|
||||
err := mox.DomainSave(ctx, domainName, func(d *config.Domain) {
|
||||
err := mox.DomainSave(ctx, domainName, func(d *config.Domain) error {
|
||||
if policyID == "" {
|
||||
d.MTASTS = nil
|
||||
} else {
|
||||
@ -2522,6 +2528,7 @@ func (Admin) DomainMTASTSSave(ctx context.Context, domainName, policyID string,
|
||||
MX: mx,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
xcheckf(ctx, err, "saving mtasts policy for domain")
|
||||
}
|
||||
@ -2557,7 +2564,7 @@ func (Admin) DomainDKIMSave(ctx context.Context, domainName string, selectors ma
|
||||
}
|
||||
}
|
||||
|
||||
err := mox.DomainSave(ctx, domainName, func(d *config.Domain) {
|
||||
err := mox.DomainSave(ctx, domainName, func(d *config.Domain) error {
|
||||
if len(selectors) != len(d.DKIM.Selectors) {
|
||||
xcheckuserf(ctx, fmt.Errorf("cannot add/remove dkim selectors with this function"), "checking selectors")
|
||||
}
|
||||
@ -2591,6 +2598,50 @@ func (Admin) DomainDKIMSave(ctx context.Context, domainName string, selectors ma
|
||||
Selectors: sels,
|
||||
Sign: sign,
|
||||
}
|
||||
return nil
|
||||
})
|
||||
xcheckf(ctx, err, "saving dkim selector for domain")
|
||||
}
|
||||
|
||||
func xparseAddress(ctx context.Context, lp, domain string) smtp.Address {
|
||||
xlp, err := smtp.ParseLocalpart(lp)
|
||||
xcheckuserf(ctx, err, "parsing localpart")
|
||||
d, err := dns.ParseDomain(domain)
|
||||
xcheckuserf(ctx, err, "parsing domain")
|
||||
return smtp.NewAddress(xlp, d)
|
||||
}
|
||||
|
||||
func (Admin) AliasAdd(ctx context.Context, aliaslp string, domainName string, alias config.Alias) {
|
||||
addr := xparseAddress(ctx, aliaslp, domainName)
|
||||
err := mox.AliasAdd(ctx, addr, alias)
|
||||
xcheckf(ctx, err, "adding alias")
|
||||
}
|
||||
|
||||
func (Admin) AliasUpdate(ctx context.Context, aliaslp string, domainName string, postPublic, listMembers, allowMsgFrom bool) {
|
||||
addr := xparseAddress(ctx, aliaslp, domainName)
|
||||
alias := config.Alias{
|
||||
PostPublic: postPublic,
|
||||
ListMembers: listMembers,
|
||||
AllowMsgFrom: allowMsgFrom,
|
||||
}
|
||||
err := mox.AliasUpdate(ctx, addr, alias)
|
||||
xcheckf(ctx, err, "saving alias")
|
||||
}
|
||||
|
||||
func (Admin) AliasRemove(ctx context.Context, aliaslp string, domainName string) {
|
||||
addr := xparseAddress(ctx, aliaslp, domainName)
|
||||
err := mox.AliasRemove(ctx, addr)
|
||||
xcheckf(ctx, err, "removing alias")
|
||||
}
|
||||
|
||||
func (Admin) AliasAddressesAdd(ctx context.Context, aliaslp string, domainName string, addresses []string) {
|
||||
addr := xparseAddress(ctx, aliaslp, domainName)
|
||||
err := mox.AliasAddressesAdd(ctx, addr, addresses)
|
||||
xcheckf(ctx, err, "adding address to alias")
|
||||
}
|
||||
|
||||
func (Admin) AliasAddressesRemove(ctx context.Context, aliaslp string, domainName string, addresses []string) {
|
||||
addr := xparseAddress(ctx, aliaslp, domainName)
|
||||
err := mox.AliasAddressesRemove(ctx, addr, addresses)
|
||||
xcheckf(ctx, err, "removing address from alias")
|
||||
}
|
||||
|
@ -337,7 +337,7 @@ var api;
|
||||
SPFResult["SPFTemperror"] = "temperror";
|
||||
SPFResult["SPFPermerror"] = "permerror";
|
||||
})(SPFResult = api.SPFResult || (api.SPFResult = {}));
|
||||
api.structTypes = { "Account": true, "AuthResults": true, "AutoconfCheckResult": true, "AutodiscoverCheckResult": true, "AutodiscoverSRV": true, "AutomaticJunkFlags": true, "Canonicalization": true, "CheckResult": true, "ClientConfigs": true, "ClientConfigsEntry": true, "ConfigDomain": true, "DANECheckResult": true, "DKIM": true, "DKIMAuthResult": true, "DKIMCheckResult": true, "DKIMRecord": true, "DMARC": true, "DMARCCheckResult": true, "DMARCRecord": true, "DMARCSummary": true, "DNSSECResult": true, "DateRange": true, "Destination": true, "Directive": true, "Domain": true, "DomainFeedback": true, "Dynamic": true, "Evaluation": true, "EvaluationStat": true, "Extension": true, "FailureDetails": true, "Filter": true, "HoldRule": true, "Hook": true, "HookFilter": true, "HookResult": true, "HookRetired": true, "HookRetiredFilter": true, "HookRetiredSort": true, "HookSort": true, "IPDomain": true, "IPRevCheckResult": true, "Identifiers": true, "IncomingWebhook": true, "JunkFilter": true, "MTASTS": true, "MTASTSCheckResult": true, "MTASTSRecord": true, "MX": true, "MXCheckResult": true, "Modifier": true, "Msg": true, "MsgResult": true, "MsgRetired": true, "OutgoingWebhook": true, "Pair": true, "Policy": true, "PolicyEvaluated": true, "PolicyOverrideReason": true, "PolicyPublished": true, "PolicyRecord": true, "Record": true, "Report": true, "ReportMetadata": true, "ReportRecord": true, "Result": true, "ResultPolicy": true, "RetiredFilter": true, "RetiredSort": true, "Reverse": true, "Route": true, "Row": true, "Ruleset": true, "SMTPAuth": true, "SPFAuthResult": true, "SPFCheckResult": true, "SPFRecord": true, "SRV": true, "SRVConfCheckResult": true, "STSMX": true, "Selector": true, "Sort": true, "SubjectPass": true, "Summary": true, "SuppressAddress": true, "TLSCheckResult": true, "TLSRPT": true, "TLSRPTCheckResult": true, "TLSRPTDateRange": true, "TLSRPTRecord": true, "TLSRPTSummary": true, "TLSRPTSuppressAddress": true, "TLSReportRecord": true, "TLSResult": true, "Transport": true, "TransportDirect": true, "TransportSMTP": true, "TransportSocks": true, "URI": true, "WebForward": true, "WebHandler": true, "WebRedirect": true, "WebStatic": true, "WebserverConfig": true };
|
||||
api.structTypes = { "Account": true, "Address": true, "AddressAlias": true, "Alias": true, "AliasAddress": true, "AuthResults": true, "AutoconfCheckResult": true, "AutodiscoverCheckResult": true, "AutodiscoverSRV": true, "AutomaticJunkFlags": true, "Canonicalization": true, "CheckResult": true, "ClientConfigs": true, "ClientConfigsEntry": true, "ConfigDomain": true, "DANECheckResult": true, "DKIM": true, "DKIMAuthResult": true, "DKIMCheckResult": true, "DKIMRecord": true, "DMARC": true, "DMARCCheckResult": true, "DMARCRecord": true, "DMARCSummary": true, "DNSSECResult": true, "DateRange": true, "Destination": true, "Directive": true, "Domain": true, "DomainFeedback": true, "Dynamic": true, "Evaluation": true, "EvaluationStat": true, "Extension": true, "FailureDetails": true, "Filter": true, "HoldRule": true, "Hook": true, "HookFilter": true, "HookResult": true, "HookRetired": true, "HookRetiredFilter": true, "HookRetiredSort": true, "HookSort": true, "IPDomain": true, "IPRevCheckResult": true, "Identifiers": true, "IncomingWebhook": true, "JunkFilter": true, "MTASTS": true, "MTASTSCheckResult": true, "MTASTSRecord": true, "MX": true, "MXCheckResult": true, "Modifier": true, "Msg": true, "MsgResult": true, "MsgRetired": true, "OutgoingWebhook": true, "Pair": true, "Policy": true, "PolicyEvaluated": true, "PolicyOverrideReason": true, "PolicyPublished": true, "PolicyRecord": true, "Record": true, "Report": true, "ReportMetadata": true, "ReportRecord": true, "Result": true, "ResultPolicy": true, "RetiredFilter": true, "RetiredSort": true, "Reverse": true, "Route": true, "Row": true, "Ruleset": true, "SMTPAuth": true, "SPFAuthResult": true, "SPFCheckResult": true, "SPFRecord": true, "SRV": true, "SRVConfCheckResult": true, "STSMX": true, "Selector": true, "Sort": true, "SubjectPass": true, "Summary": true, "SuppressAddress": true, "TLSCheckResult": true, "TLSRPT": true, "TLSRPTCheckResult": true, "TLSRPTDateRange": true, "TLSRPTRecord": true, "TLSRPTSummary": true, "TLSRPTSuppressAddress": true, "TLSReportRecord": true, "TLSResult": true, "Transport": true, "TransportDirect": true, "TransportSMTP": true, "TransportSocks": true, "URI": true, "WebForward": true, "WebHandler": true, "WebRedirect": true, "WebStatic": true, "WebserverConfig": true };
|
||||
api.stringsTypes = { "Align": true, "Alignment": true, "CSRFToken": true, "DKIMResult": true, "DMARCPolicy": true, "DMARCResult": true, "Disposition": true, "IP": true, "Localpart": true, "Mode": true, "PolicyOverride": true, "PolicyType": true, "RUA": true, "ResultType": true, "SPFDomainScope": true, "SPFResult": true };
|
||||
api.intsTypes = {};
|
||||
api.types = {
|
||||
@ -372,7 +372,7 @@ var api;
|
||||
"AutoconfCheckResult": { "Name": "AutoconfCheckResult", "Docs": "", "Fields": [{ "Name": "ClientSettingsDomainIPs", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "IPs", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "Errors", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "Warnings", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "Instructions", "Docs": "", "Typewords": ["[]", "string"] }] },
|
||||
"AutodiscoverCheckResult": { "Name": "AutodiscoverCheckResult", "Docs": "", "Fields": [{ "Name": "Records", "Docs": "", "Typewords": ["[]", "AutodiscoverSRV"] }, { "Name": "Errors", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "Warnings", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "Instructions", "Docs": "", "Typewords": ["[]", "string"] }] },
|
||||
"AutodiscoverSRV": { "Name": "AutodiscoverSRV", "Docs": "", "Fields": [{ "Name": "Target", "Docs": "", "Typewords": ["string"] }, { "Name": "Port", "Docs": "", "Typewords": ["uint16"] }, { "Name": "Priority", "Docs": "", "Typewords": ["uint16"] }, { "Name": "Weight", "Docs": "", "Typewords": ["uint16"] }, { "Name": "IPs", "Docs": "", "Typewords": ["[]", "string"] }] },
|
||||
"ConfigDomain": { "Name": "ConfigDomain", "Docs": "", "Fields": [{ "Name": "Description", "Docs": "", "Typewords": ["string"] }, { "Name": "ClientSettingsDomain", "Docs": "", "Typewords": ["string"] }, { "Name": "LocalpartCatchallSeparator", "Docs": "", "Typewords": ["string"] }, { "Name": "LocalpartCaseSensitive", "Docs": "", "Typewords": ["bool"] }, { "Name": "DKIM", "Docs": "", "Typewords": ["DKIM"] }, { "Name": "DMARC", "Docs": "", "Typewords": ["nullable", "DMARC"] }, { "Name": "MTASTS", "Docs": "", "Typewords": ["nullable", "MTASTS"] }, { "Name": "TLSRPT", "Docs": "", "Typewords": ["nullable", "TLSRPT"] }, { "Name": "Routes", "Docs": "", "Typewords": ["[]", "Route"] }] },
|
||||
"ConfigDomain": { "Name": "ConfigDomain", "Docs": "", "Fields": [{ "Name": "Description", "Docs": "", "Typewords": ["string"] }, { "Name": "ClientSettingsDomain", "Docs": "", "Typewords": ["string"] }, { "Name": "LocalpartCatchallSeparator", "Docs": "", "Typewords": ["string"] }, { "Name": "LocalpartCaseSensitive", "Docs": "", "Typewords": ["bool"] }, { "Name": "DKIM", "Docs": "", "Typewords": ["DKIM"] }, { "Name": "DMARC", "Docs": "", "Typewords": ["nullable", "DMARC"] }, { "Name": "MTASTS", "Docs": "", "Typewords": ["nullable", "MTASTS"] }, { "Name": "TLSRPT", "Docs": "", "Typewords": ["nullable", "TLSRPT"] }, { "Name": "Routes", "Docs": "", "Typewords": ["[]", "Route"] }, { "Name": "Aliases", "Docs": "", "Typewords": ["{}", "Alias"] }, { "Name": "Domain", "Docs": "", "Typewords": ["Domain"] }] },
|
||||
"DKIM": { "Name": "DKIM", "Docs": "", "Fields": [{ "Name": "Selectors", "Docs": "", "Typewords": ["{}", "Selector"] }, { "Name": "Sign", "Docs": "", "Typewords": ["[]", "string"] }] },
|
||||
"Selector": { "Name": "Selector", "Docs": "", "Fields": [{ "Name": "Hash", "Docs": "", "Typewords": ["string"] }, { "Name": "HashEffective", "Docs": "", "Typewords": ["string"] }, { "Name": "Canonicalization", "Docs": "", "Typewords": ["Canonicalization"] }, { "Name": "Headers", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "HeadersEffective", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "DontSealHeaders", "Docs": "", "Typewords": ["bool"] }, { "Name": "Expiration", "Docs": "", "Typewords": ["string"] }, { "Name": "PrivateKeyFile", "Docs": "", "Typewords": ["string"] }, { "Name": "Algorithm", "Docs": "", "Typewords": ["string"] }] },
|
||||
"Canonicalization": { "Name": "Canonicalization", "Docs": "", "Fields": [{ "Name": "HeaderRelaxed", "Docs": "", "Typewords": ["bool"] }, { "Name": "BodyRelaxed", "Docs": "", "Typewords": ["bool"] }] },
|
||||
@ -380,14 +380,18 @@ var api;
|
||||
"MTASTS": { "Name": "MTASTS", "Docs": "", "Fields": [{ "Name": "PolicyID", "Docs": "", "Typewords": ["string"] }, { "Name": "Mode", "Docs": "", "Typewords": ["Mode"] }, { "Name": "MaxAge", "Docs": "", "Typewords": ["int64"] }, { "Name": "MX", "Docs": "", "Typewords": ["[]", "string"] }] },
|
||||
"TLSRPT": { "Name": "TLSRPT", "Docs": "", "Fields": [{ "Name": "Localpart", "Docs": "", "Typewords": ["string"] }, { "Name": "Domain", "Docs": "", "Typewords": ["string"] }, { "Name": "Account", "Docs": "", "Typewords": ["string"] }, { "Name": "Mailbox", "Docs": "", "Typewords": ["string"] }, { "Name": "ParsedLocalpart", "Docs": "", "Typewords": ["Localpart"] }, { "Name": "DNSDomain", "Docs": "", "Typewords": ["Domain"] }] },
|
||||
"Route": { "Name": "Route", "Docs": "", "Fields": [{ "Name": "FromDomain", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "ToDomain", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "MinimumAttempts", "Docs": "", "Typewords": ["int32"] }, { "Name": "Transport", "Docs": "", "Typewords": ["string"] }, { "Name": "FromDomainASCII", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "ToDomainASCII", "Docs": "", "Typewords": ["[]", "string"] }] },
|
||||
"Account": { "Name": "Account", "Docs": "", "Fields": [{ "Name": "OutgoingWebhook", "Docs": "", "Typewords": ["nullable", "OutgoingWebhook"] }, { "Name": "IncomingWebhook", "Docs": "", "Typewords": ["nullable", "IncomingWebhook"] }, { "Name": "FromIDLoginAddresses", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "KeepRetiredMessagePeriod", "Docs": "", "Typewords": ["int64"] }, { "Name": "KeepRetiredWebhookPeriod", "Docs": "", "Typewords": ["int64"] }, { "Name": "Domain", "Docs": "", "Typewords": ["string"] }, { "Name": "Description", "Docs": "", "Typewords": ["string"] }, { "Name": "FullName", "Docs": "", "Typewords": ["string"] }, { "Name": "Destinations", "Docs": "", "Typewords": ["{}", "Destination"] }, { "Name": "SubjectPass", "Docs": "", "Typewords": ["SubjectPass"] }, { "Name": "QuotaMessageSize", "Docs": "", "Typewords": ["int64"] }, { "Name": "RejectsMailbox", "Docs": "", "Typewords": ["string"] }, { "Name": "KeepRejects", "Docs": "", "Typewords": ["bool"] }, { "Name": "AutomaticJunkFlags", "Docs": "", "Typewords": ["AutomaticJunkFlags"] }, { "Name": "JunkFilter", "Docs": "", "Typewords": ["nullable", "JunkFilter"] }, { "Name": "MaxOutgoingMessagesPerDay", "Docs": "", "Typewords": ["int32"] }, { "Name": "MaxFirstTimeRecipientsPerDay", "Docs": "", "Typewords": ["int32"] }, { "Name": "NoFirstTimeSenderDelay", "Docs": "", "Typewords": ["bool"] }, { "Name": "Routes", "Docs": "", "Typewords": ["[]", "Route"] }, { "Name": "DNSDomain", "Docs": "", "Typewords": ["Domain"] }] },
|
||||
"OutgoingWebhook": { "Name": "OutgoingWebhook", "Docs": "", "Fields": [{ "Name": "URL", "Docs": "", "Typewords": ["string"] }, { "Name": "Authorization", "Docs": "", "Typewords": ["string"] }, { "Name": "Events", "Docs": "", "Typewords": ["[]", "string"] }] },
|
||||
"IncomingWebhook": { "Name": "IncomingWebhook", "Docs": "", "Fields": [{ "Name": "URL", "Docs": "", "Typewords": ["string"] }, { "Name": "Authorization", "Docs": "", "Typewords": ["string"] }] },
|
||||
"Alias": { "Name": "Alias", "Docs": "", "Fields": [{ "Name": "Addresses", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "PostPublic", "Docs": "", "Typewords": ["bool"] }, { "Name": "ListMembers", "Docs": "", "Typewords": ["bool"] }, { "Name": "AllowMsgFrom", "Docs": "", "Typewords": ["bool"] }, { "Name": "LocalpartStr", "Docs": "", "Typewords": ["string"] }, { "Name": "Domain", "Docs": "", "Typewords": ["Domain"] }, { "Name": "ParsedAddresses", "Docs": "", "Typewords": ["[]", "AliasAddress"] }] },
|
||||
"AliasAddress": { "Name": "AliasAddress", "Docs": "", "Fields": [{ "Name": "Address", "Docs": "", "Typewords": ["Address"] }, { "Name": "AccountName", "Docs": "", "Typewords": ["string"] }, { "Name": "Destination", "Docs": "", "Typewords": ["Destination"] }] },
|
||||
"Address": { "Name": "Address", "Docs": "", "Fields": [{ "Name": "Localpart", "Docs": "", "Typewords": ["Localpart"] }, { "Name": "Domain", "Docs": "", "Typewords": ["Domain"] }] },
|
||||
"Destination": { "Name": "Destination", "Docs": "", "Fields": [{ "Name": "Mailbox", "Docs": "", "Typewords": ["string"] }, { "Name": "Rulesets", "Docs": "", "Typewords": ["[]", "Ruleset"] }, { "Name": "FullName", "Docs": "", "Typewords": ["string"] }] },
|
||||
"Ruleset": { "Name": "Ruleset", "Docs": "", "Fields": [{ "Name": "SMTPMailFromRegexp", "Docs": "", "Typewords": ["string"] }, { "Name": "MsgFromRegexp", "Docs": "", "Typewords": ["string"] }, { "Name": "VerifiedDomain", "Docs": "", "Typewords": ["string"] }, { "Name": "HeadersRegexp", "Docs": "", "Typewords": ["{}", "string"] }, { "Name": "IsForward", "Docs": "", "Typewords": ["bool"] }, { "Name": "ListAllowDomain", "Docs": "", "Typewords": ["string"] }, { "Name": "AcceptRejectsToMailbox", "Docs": "", "Typewords": ["string"] }, { "Name": "Mailbox", "Docs": "", "Typewords": ["string"] }, { "Name": "Comment", "Docs": "", "Typewords": ["string"] }, { "Name": "VerifiedDNSDomain", "Docs": "", "Typewords": ["Domain"] }, { "Name": "ListAllowDNSDomain", "Docs": "", "Typewords": ["Domain"] }] },
|
||||
"Account": { "Name": "Account", "Docs": "", "Fields": [{ "Name": "OutgoingWebhook", "Docs": "", "Typewords": ["nullable", "OutgoingWebhook"] }, { "Name": "IncomingWebhook", "Docs": "", "Typewords": ["nullable", "IncomingWebhook"] }, { "Name": "FromIDLoginAddresses", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "KeepRetiredMessagePeriod", "Docs": "", "Typewords": ["int64"] }, { "Name": "KeepRetiredWebhookPeriod", "Docs": "", "Typewords": ["int64"] }, { "Name": "Domain", "Docs": "", "Typewords": ["string"] }, { "Name": "Description", "Docs": "", "Typewords": ["string"] }, { "Name": "FullName", "Docs": "", "Typewords": ["string"] }, { "Name": "Destinations", "Docs": "", "Typewords": ["{}", "Destination"] }, { "Name": "SubjectPass", "Docs": "", "Typewords": ["SubjectPass"] }, { "Name": "QuotaMessageSize", "Docs": "", "Typewords": ["int64"] }, { "Name": "RejectsMailbox", "Docs": "", "Typewords": ["string"] }, { "Name": "KeepRejects", "Docs": "", "Typewords": ["bool"] }, { "Name": "AutomaticJunkFlags", "Docs": "", "Typewords": ["AutomaticJunkFlags"] }, { "Name": "JunkFilter", "Docs": "", "Typewords": ["nullable", "JunkFilter"] }, { "Name": "MaxOutgoingMessagesPerDay", "Docs": "", "Typewords": ["int32"] }, { "Name": "MaxFirstTimeRecipientsPerDay", "Docs": "", "Typewords": ["int32"] }, { "Name": "NoFirstTimeSenderDelay", "Docs": "", "Typewords": ["bool"] }, { "Name": "Routes", "Docs": "", "Typewords": ["[]", "Route"] }, { "Name": "DNSDomain", "Docs": "", "Typewords": ["Domain"] }, { "Name": "Aliases", "Docs": "", "Typewords": ["[]", "AddressAlias"] }] },
|
||||
"OutgoingWebhook": { "Name": "OutgoingWebhook", "Docs": "", "Fields": [{ "Name": "URL", "Docs": "", "Typewords": ["string"] }, { "Name": "Authorization", "Docs": "", "Typewords": ["string"] }, { "Name": "Events", "Docs": "", "Typewords": ["[]", "string"] }] },
|
||||
"IncomingWebhook": { "Name": "IncomingWebhook", "Docs": "", "Fields": [{ "Name": "URL", "Docs": "", "Typewords": ["string"] }, { "Name": "Authorization", "Docs": "", "Typewords": ["string"] }] },
|
||||
"SubjectPass": { "Name": "SubjectPass", "Docs": "", "Fields": [{ "Name": "Period", "Docs": "", "Typewords": ["int64"] }] },
|
||||
"AutomaticJunkFlags": { "Name": "AutomaticJunkFlags", "Docs": "", "Fields": [{ "Name": "Enabled", "Docs": "", "Typewords": ["bool"] }, { "Name": "JunkMailboxRegexp", "Docs": "", "Typewords": ["string"] }, { "Name": "NeutralMailboxRegexp", "Docs": "", "Typewords": ["string"] }, { "Name": "NotJunkMailboxRegexp", "Docs": "", "Typewords": ["string"] }] },
|
||||
"JunkFilter": { "Name": "JunkFilter", "Docs": "", "Fields": [{ "Name": "Threshold", "Docs": "", "Typewords": ["float64"] }, { "Name": "Onegrams", "Docs": "", "Typewords": ["bool"] }, { "Name": "Twograms", "Docs": "", "Typewords": ["bool"] }, { "Name": "Threegrams", "Docs": "", "Typewords": ["bool"] }, { "Name": "MaxPower", "Docs": "", "Typewords": ["float64"] }, { "Name": "TopWords", "Docs": "", "Typewords": ["int32"] }, { "Name": "IgnoreWords", "Docs": "", "Typewords": ["float64"] }, { "Name": "RareWords", "Docs": "", "Typewords": ["int32"] }] },
|
||||
"AddressAlias": { "Name": "AddressAlias", "Docs": "", "Fields": [{ "Name": "SubscriptionAddress", "Docs": "", "Typewords": ["string"] }, { "Name": "Alias", "Docs": "", "Typewords": ["Alias"] }, { "Name": "MemberAddresses", "Docs": "", "Typewords": ["[]", "string"] }] },
|
||||
"PolicyRecord": { "Name": "PolicyRecord", "Docs": "", "Fields": [{ "Name": "Domain", "Docs": "", "Typewords": ["string"] }, { "Name": "Inserted", "Docs": "", "Typewords": ["timestamp"] }, { "Name": "ValidEnd", "Docs": "", "Typewords": ["timestamp"] }, { "Name": "LastUpdate", "Docs": "", "Typewords": ["timestamp"] }, { "Name": "LastUse", "Docs": "", "Typewords": ["timestamp"] }, { "Name": "Backoff", "Docs": "", "Typewords": ["bool"] }, { "Name": "RecordID", "Docs": "", "Typewords": ["string"] }, { "Name": "Version", "Docs": "", "Typewords": ["string"] }, { "Name": "Mode", "Docs": "", "Typewords": ["Mode"] }, { "Name": "MX", "Docs": "", "Typewords": ["[]", "STSMX"] }, { "Name": "MaxAgeSeconds", "Docs": "", "Typewords": ["int32"] }, { "Name": "Extensions", "Docs": "", "Typewords": ["[]", "Pair"] }, { "Name": "PolicyText", "Docs": "", "Typewords": ["string"] }] },
|
||||
"TLSReportRecord": { "Name": "TLSReportRecord", "Docs": "", "Fields": [{ "Name": "ID", "Docs": "", "Typewords": ["int64"] }, { "Name": "Domain", "Docs": "", "Typewords": ["string"] }, { "Name": "FromDomain", "Docs": "", "Typewords": ["string"] }, { "Name": "MailFrom", "Docs": "", "Typewords": ["string"] }, { "Name": "HostReport", "Docs": "", "Typewords": ["bool"] }, { "Name": "Report", "Docs": "", "Typewords": ["Report"] }] },
|
||||
"Report": { "Name": "Report", "Docs": "", "Fields": [{ "Name": "OrganizationName", "Docs": "", "Typewords": ["string"] }, { "Name": "DateRange", "Docs": "", "Typewords": ["TLSRPTDateRange"] }, { "Name": "ContactInfo", "Docs": "", "Typewords": ["string"] }, { "Name": "ReportID", "Docs": "", "Typewords": ["string"] }, { "Name": "Policies", "Docs": "", "Typewords": ["[]", "Result"] }] },
|
||||
@ -502,14 +506,18 @@ var api;
|
||||
MTASTS: (v) => api.parse("MTASTS", v),
|
||||
TLSRPT: (v) => api.parse("TLSRPT", v),
|
||||
Route: (v) => api.parse("Route", v),
|
||||
Alias: (v) => api.parse("Alias", v),
|
||||
AliasAddress: (v) => api.parse("AliasAddress", v),
|
||||
Address: (v) => api.parse("Address", v),
|
||||
Destination: (v) => api.parse("Destination", v),
|
||||
Ruleset: (v) => api.parse("Ruleset", v),
|
||||
Account: (v) => api.parse("Account", v),
|
||||
OutgoingWebhook: (v) => api.parse("OutgoingWebhook", v),
|
||||
IncomingWebhook: (v) => api.parse("IncomingWebhook", v),
|
||||
Destination: (v) => api.parse("Destination", v),
|
||||
Ruleset: (v) => api.parse("Ruleset", v),
|
||||
SubjectPass: (v) => api.parse("SubjectPass", v),
|
||||
AutomaticJunkFlags: (v) => api.parse("AutomaticJunkFlags", v),
|
||||
JunkFilter: (v) => api.parse("JunkFilter", v),
|
||||
AddressAlias: (v) => api.parse("AddressAlias", v),
|
||||
PolicyRecord: (v) => api.parse("PolicyRecord", v),
|
||||
TLSReportRecord: (v) => api.parse("TLSReportRecord", v),
|
||||
Report: (v) => api.parse("Report", v),
|
||||
@ -680,7 +688,7 @@ var api;
|
||||
async DomainLocalparts(domain) {
|
||||
const fn = "DomainLocalparts";
|
||||
const paramTypes = [["string"]];
|
||||
const returnTypes = [["{}", "string"]];
|
||||
const returnTypes = [["{}", "string"], ["{}", "Alias"]];
|
||||
const params = [domain];
|
||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params);
|
||||
}
|
||||
@ -1351,6 +1359,41 @@ var api;
|
||||
const params = [domainName, selectors, sign];
|
||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params);
|
||||
}
|
||||
async AliasAdd(aliaslp, domainName, alias) {
|
||||
const fn = "AliasAdd";
|
||||
const paramTypes = [["string"], ["string"], ["Alias"]];
|
||||
const returnTypes = [];
|
||||
const params = [aliaslp, domainName, alias];
|
||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params);
|
||||
}
|
||||
async AliasUpdate(aliaslp, domainName, postPublic, listMembers, allowMsgFrom) {
|
||||
const fn = "AliasUpdate";
|
||||
const paramTypes = [["string"], ["string"], ["bool"], ["bool"], ["bool"]];
|
||||
const returnTypes = [];
|
||||
const params = [aliaslp, domainName, postPublic, listMembers, allowMsgFrom];
|
||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params);
|
||||
}
|
||||
async AliasRemove(aliaslp, domainName) {
|
||||
const fn = "AliasRemove";
|
||||
const paramTypes = [["string"], ["string"]];
|
||||
const returnTypes = [];
|
||||
const params = [aliaslp, domainName];
|
||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params);
|
||||
}
|
||||
async AliasAddressesAdd(aliaslp, domainName, addresses) {
|
||||
const fn = "AliasAddressesAdd";
|
||||
const paramTypes = [["string"], ["string"], ["[]", "string"]];
|
||||
const returnTypes = [];
|
||||
const params = [aliaslp, domainName, addresses];
|
||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params);
|
||||
}
|
||||
async AliasAddressesRemove(aliaslp, domainName, addresses) {
|
||||
const fn = "AliasAddressesRemove";
|
||||
const paramTypes = [["string"], ["string"], ["[]", "string"]];
|
||||
const returnTypes = [];
|
||||
const params = [aliaslp, domainName, addresses];
|
||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params);
|
||||
}
|
||||
}
|
||||
api.Client = Client;
|
||||
api.defaultBaseURL = (function () {
|
||||
@ -2221,7 +2264,10 @@ const account = async (name) => {
|
||||
await check(fieldset, client.AddressAdd(address, name));
|
||||
form.reset();
|
||||
window.location.reload(); // todo: only reload the destinations
|
||||
}, fieldset = dom.fieldset(dom.label(style({ display: 'inline-block' }), dom.span('Localpart', attr.title('The localpart is the part before the "@"-sign of an email address. If empty, a catchall address is configured for the domain.')), dom.br(), localpart = dom.input()), '@', dom.label(style({ display: 'inline-block' }), dom.span('Domain'), dom.br(), domain = dom.select((domains || []).map(d => dom.option(domainName(d), domainName(d) === config.Domain ? attr.selected('') : [])))), ' ', dom.submitbutton('Add address'))), dom.br(), dom.h2('Settings'), dom.form(fieldsetSettings = dom.fieldset(dom.label(style({ display: 'block', marginBottom: '.5ex' }), dom.span('Maximum outgoing messages per day', attr.title('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 in configuration file.')), dom.br(), maxOutgoingMessagesPerDay = dom.input(attr.type('number'), attr.required(''), attr.value('' + (config.MaxOutgoingMessagesPerDay || 1000)))), dom.label(style({ display: 'block', marginBottom: '.5ex' }), dom.span('Maximum first-time recipients per day', attr.title('Maximum number of first-time recipients in 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 200. MaxFirstTimeRecipientsPerDay in configuration file.')), dom.br(), maxFirstTimeRecipientsPerDay = dom.input(attr.type('number'), attr.required(''), attr.value('' + (config.MaxFirstTimeRecipientsPerDay || 200)))), dom.label(style({ display: 'block', marginBottom: '.5ex' }), dom.span('Disk usage quota: Maximum total message size ', attr.title('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.')), dom.br(), quotaMessageSize = dom.input(attr.value(formatQuotaSize(config.QuotaMessageSize))), ' Current usage is ', formatQuotaSize(Math.floor(diskUsage / (1024 * 1024)) * 1024 * 1024), '.'), dom.div(style({ display: 'block', marginBottom: '.5ex' }), dom.label(firstTimeSenderDelay = dom.input(attr.type('checkbox'), config.NoFirstTimeSenderDelay ? [] : attr.checked('')), ' ', dom.span('Delay deliveries from first-time senders.', attr.title('To slow down potential spammers, when the message is misclassified as non-junk. Turning off the delay can be useful when the account processes messages automatically and needs fast responses.')))), dom.submitbutton('Save')), async function submit(e) {
|
||||
}, fieldset = dom.fieldset(dom.label(style({ display: 'inline-block' }), dom.span('Localpart', attr.title('The localpart is the part before the "@"-sign of an email address. If empty, a catchall address is configured for the domain.')), dom.br(), localpart = dom.input()), '@', dom.label(style({ display: 'inline-block' }), dom.span('Domain'), dom.br(), domain = dom.select((domains || []).map(d => dom.option(domainName(d), domainName(d) === config.Domain ? attr.selected('') : [])))), ' ', dom.submitbutton('Add address'))), dom.br(), dom.h2('Aliases/lists'), dom.table(dom.thead(dom.tr(dom.th('Alias address'), dom.th('Subscription address'), dom.th('Allowed senders', attr.title('Whether only members can send through the alias/list, or anyone.')), dom.th('Send as alias address', attr.title('If enabled, messages can be sent with the alias address in the message "From" header.')), dom.th('Members visible', attr.title('If enabled, members can see the addresses of other members.')))), (config.Aliases || []).length === 0 ? dom.tr(dom.td(attr.colspan('6'), 'None')) : [], (config.Aliases || []).sort((a, b) => a.Alias.LocalpartStr < b.Alias.LocalpartStr ? -1 : (domainName(a.Alias.Domain) < domainName(b.Alias.Domain) ? -1 : 1)).map(a => dom.tr(dom.td(dom.a(a.Alias.LocalpartStr, '@', domainName(a.Alias.Domain), attr.href('#domains/' + domainName(a.Alias.Domain) + '/alias/' + encodeURIComponent(a.Alias.LocalpartStr)))), dom.td(a.SubscriptionAddress), dom.td(a.Alias.PostPublic ? 'Anyone' : 'Members only'), dom.td(a.Alias.AllowMsgFrom ? 'Yes' : 'No'), dom.td(a.Alias.ListMembers ? 'Yes' : 'No'), dom.td(dom.clickbutton('Remove', async function click(e) {
|
||||
await check(e.target, client.AliasAddressesRemove(a.Alias.LocalpartStr, domainName(a.Alias.Domain), [a.SubscriptionAddress]));
|
||||
window.location.reload(); // todo: reload less
|
||||
}))))), dom.br(), dom.h2('Settings'), dom.form(fieldsetSettings = dom.fieldset(dom.label(style({ display: 'block', marginBottom: '.5ex' }), dom.span('Maximum outgoing messages per day', attr.title('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 in configuration file.')), dom.br(), maxOutgoingMessagesPerDay = dom.input(attr.type('number'), attr.required(''), attr.value('' + (config.MaxOutgoingMessagesPerDay || 1000)))), dom.label(style({ display: 'block', marginBottom: '.5ex' }), dom.span('Maximum first-time recipients per day', attr.title('Maximum number of first-time recipients in 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 200. MaxFirstTimeRecipientsPerDay in configuration file.')), dom.br(), maxFirstTimeRecipientsPerDay = dom.input(attr.type('number'), attr.required(''), attr.value('' + (config.MaxFirstTimeRecipientsPerDay || 200)))), dom.label(style({ display: 'block', marginBottom: '.5ex' }), dom.span('Disk usage quota: Maximum total message size ', attr.title('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.')), dom.br(), quotaMessageSize = dom.input(attr.value(formatQuotaSize(config.QuotaMessageSize))), ' Current usage is ', formatQuotaSize(Math.floor(diskUsage / (1024 * 1024)) * 1024 * 1024), '.'), dom.div(style({ display: 'block', marginBottom: '.5ex' }), dom.label(firstTimeSenderDelay = dom.input(attr.type('checkbox'), config.NoFirstTimeSenderDelay ? [] : attr.checked('')), ' ', dom.span('Delay deliveries from first-time senders.', attr.title('To slow down potential spammers, when the message is misclassified as non-junk. Turning off the delay can be useful when the account processes messages automatically and needs fast responses.')))), dom.submitbutton('Save')), async function submit(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
await check(fieldsetSettings, client.AccountSettingsSave(name, parseInt(maxOutgoingMessagesPerDay.value) || 0, parseInt(maxFirstTimeRecipientsPerDay.value) || 0, xparseSize(quotaMessageSize.value), firstTimeSenderDelay.checked));
|
||||
@ -2312,7 +2358,7 @@ const formatDuration = (v, goDuration) => {
|
||||
const domain = async (d) => {
|
||||
const end = new Date();
|
||||
const start = new Date(new Date().getTime() - 30 * 24 * 3600 * 1000);
|
||||
const [dmarcSummaries, tlsrptSummaries, localpartAccounts, dnsdomain, clientConfigs, accounts, domainConfig, transports] = await Promise.all([
|
||||
const [dmarcSummaries, tlsrptSummaries, [localpartAccounts, localpartAliases], dnsdomain, clientConfigs, accounts, domainConfig, transports] = await Promise.all([
|
||||
client.DMARCSummaries(start, end, d),
|
||||
client.TLSRPTSummaries(start, end, d),
|
||||
client.DomainLocalparts(d),
|
||||
@ -2326,6 +2372,9 @@ const domain = async (d) => {
|
||||
let addrFieldset;
|
||||
let addrLocalpart;
|
||||
let addrAccount;
|
||||
let aliasFieldset;
|
||||
let aliasLocalpart;
|
||||
let aliasAddresses;
|
||||
let descrFieldset;
|
||||
let descrText;
|
||||
let clientSettingsDomainFieldset;
|
||||
@ -2401,7 +2450,23 @@ const domain = async (d) => {
|
||||
await check(addrFieldset, client.AddressAdd(addrLocalpart.value + '@' + d, addrAccount.value));
|
||||
addrForm.reset();
|
||||
window.location.reload(); // todo: only reload the addresses
|
||||
}, addrFieldset = dom.fieldset(dom.label(style({ display: 'inline-block' }), dom.span('Localpart', attr.title('The localpart is the part before the "@"-sign of an address. An empty localpart is the catchall destination/address for the domain.')), dom.br(), addrLocalpart = dom.input()), '@', domainName(dnsdomain), ' ', dom.label(style({ display: 'inline-block' }), dom.span('Account', attr.title('Account to assign the address to.')), dom.br(), addrAccount = dom.select(attr.required(''), (accounts || []).map(a => dom.option(a)))), ' ', dom.submitbutton('Add address', attr.title('Address will be added and the config reloaded.')))), dom.br(), RoutesEditor('domain-specific', transports, domainConfig.Routes || [], async (routes) => await client.DomainRoutesSave(d, routes)), dom.br(), dom.h2('Settings'), dom.form(async function submit(e) {
|
||||
}, addrFieldset = dom.fieldset(dom.label(style({ display: 'inline-block' }), dom.span('Localpart', attr.title('The localpart is the part before the "@"-sign of an address. An empty localpart is the catchall destination/address for the domain.')), dom.br(), addrLocalpart = dom.input()), '@', domainName(dnsdomain), ' ', dom.label(style({ display: 'inline-block' }), dom.span('Account', attr.title('Account to assign the address to.')), dom.br(), addrAccount = dom.select(attr.required(''), (accounts || []).map(a => dom.option(a)))), ' ', dom.submitbutton('Add address', attr.title('Address will be added and the config reloaded.')))), dom.br(), dom.h2('Aliases/lists'), dom.table(dom.thead(dom.tr(dom.th('Address'), dom.th('Allowed senders', attr.title('Whether only members can send through the alias/list, or anyone.')), dom.th('Send as alias address', attr.title('If enabled, messages can be sent with the alias address in the message "From" header.')), dom.th('Members visible', attr.title('If enabled, members can see the addresses of other members.')))), Object.values(localpartAliases).length === 0 ? dom.tr(dom.td(attr.colspan('4'), 'None')) : [], Object.values(localpartAliases).sort((a, b) => a.LocalpartStr < b.LocalpartStr ? -1 : 1).map(a => {
|
||||
return dom.tr(dom.td(dom.a(a.LocalpartStr, attr.href('#domains/' + d + '/alias/' + encodeURIComponent(a.LocalpartStr)))), dom.td(a.PostPublic ? 'Anyone' : 'Members only'), dom.td(a.AllowMsgFrom ? 'Yes' : 'No'), dom.td(a.ListMembers ? 'Yes' : 'No'));
|
||||
})), dom.br(), dom.h2('Add alias'), dom.form(async function submit(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const alias = {
|
||||
Addresses: aliasAddresses.value.split('\n').map(s => s.trim()).filter(s => !!s),
|
||||
PostPublic: false,
|
||||
ListMembers: false,
|
||||
AllowMsgFrom: false,
|
||||
// Ignored:
|
||||
LocalpartStr: '',
|
||||
Domain: dnsdomain,
|
||||
};
|
||||
await check(aliasFieldset, client.AliasAdd(aliasLocalpart.value, d, alias));
|
||||
window.location.hash = '#domains/' + d + '/alias/' + aliasLocalpart.value;
|
||||
}, aliasFieldset = dom.fieldset(style({ display: 'flex', alignItems: 'flex-start', gap: '1em' }), dom.label(dom.div('Localpart', attr.title('The localpart is the part before the "@"-sign of an address.')), aliasLocalpart = dom.input(attr.required('')), '@', domainName(dnsdomain), ' '), dom.label(dom.div('Addresses', attr.title('One members address per line, full address of form localpart@domain. At least one address required.')), aliasAddresses = dom.textarea(attr.required(''), attr.rows('1'), function focus() { aliasAddresses.setAttribute('rows', '5'); })), dom.div(dom.div('\u00a0'), dom.submitbutton('Add alias', attr.title('Alias will be added and the config reloaded.'))))), dom.br(), RoutesEditor('domain-specific', transports, domainConfig.Routes || [], async (routes) => await client.DomainRoutesSave(d, routes)), dom.br(), dom.h2('Settings'), dom.form(async function submit(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
await check(descrFieldset, client.DomainDescriptionSave(d, descrText.value));
|
||||
@ -2571,6 +2636,44 @@ const domain = async (d) => {
|
||||
window.location.hash = '#';
|
||||
}));
|
||||
};
|
||||
const domainAlias = async (d, aliasLocalpart) => {
|
||||
const domain = await client.DomainConfig(d);
|
||||
const alias = (domain.Aliases || {})[aliasLocalpart];
|
||||
if (!alias) {
|
||||
throw new Error('alias not found');
|
||||
}
|
||||
let aliasFieldset;
|
||||
let postPublic;
|
||||
let listMembers;
|
||||
let allowMsgFrom;
|
||||
let addFieldset;
|
||||
let addAddress;
|
||||
let delFieldset;
|
||||
dom._kids(page, crumbs(crumblink('Mox Admin', '#'), crumblink('Domain ' + domainString(domain.Domain), '#domains/' + d), 'Alias ' + aliasLocalpart + '@' + domainName(domain.Domain)), dom.h2('Alias'), dom.form(async function submit(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
check(aliasFieldset, client.AliasUpdate(aliasLocalpart, d, postPublic.checked, listMembers.checked, allowMsgFrom.checked));
|
||||
}, aliasFieldset = dom.fieldset(style({ display: 'flex', flexDirection: 'column', gap: '.5ex' }), dom.label(postPublic = dom.input(attr.type('checkbox'), alias.PostPublic ? attr.checked('') : []), ' Public, anyone can post instead of only members'), dom.label(listMembers = dom.input(attr.type('checkbox'), alias.ListMembers ? attr.checked('') : []), ' Members can list other members'), dom.label(allowMsgFrom = dom.input(attr.type('checkbox'), alias.AllowMsgFrom ? attr.checked('') : []), ' Allow messages to use the alias address in the message From header'), dom.div(style({ marginTop: '1ex' }), dom.submitbutton('Save')))), dom.br(), dom.h2('Members'), dom.table(dom.thead(dom.tr(dom.th('Address'), dom.th('Account'), dom.th())), dom.tbody((alias.Addresses || []).map((address, index) => {
|
||||
const pa = (alias.ParsedAddresses || [])[index];
|
||||
return dom.tr(dom.td(address), dom.td(dom.a(pa.AccountName, attr.href('#accounts/' + pa.AccountName))), dom.td(dom.clickbutton('Remove', async function click(e) {
|
||||
await check(e.target, client.AliasAddressesRemove(aliasLocalpart, d, [address]));
|
||||
window.location.reload(); // todo: reload less
|
||||
})));
|
||||
})), dom.tfoot(dom.tr(dom.td(attr.colspan('3'), dom.form(async function submit(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
await check(addFieldset, client.AliasAddressesAdd(aliasLocalpart, d, addAddress.value.split('\n').map(s => s.trim()).filter(s => s)));
|
||||
window.location.reload(); // todo: reload less
|
||||
}, addFieldset = dom.fieldset(addAddress = dom.textarea(attr.required(''), attr.rows('1'), attr.placeholder('localpart@domain'), function focus() { addAddress.setAttribute('rows', '5'); }), ' ', dom.submitbutton('Add', style({ verticalAlign: 'top' })))))))), dom.br(), dom.h2('Danger'), dom.form(async function submit(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (!confirm('Are you sure you want to remove this alias?')) {
|
||||
return;
|
||||
}
|
||||
await check(delFieldset, client.AliasRemove(aliasLocalpart, d));
|
||||
window.location.hash = '#domains/' + d;
|
||||
}, delFieldset = dom.fieldset(dom.div(dom.submitbutton('Remove alias')))));
|
||||
};
|
||||
const domainDNSRecords = async (d) => {
|
||||
const [records, dnsdomain] = await Promise.all([
|
||||
client.DomainRecords(d),
|
||||
@ -4011,6 +4114,9 @@ const init = async () => {
|
||||
else if (t[0] === 'domains' && t.length === 2) {
|
||||
await domain(t[1]);
|
||||
}
|
||||
else if (t[0] === 'domains' && t.length === 4 && t[2] === 'alias') {
|
||||
await domainAlias(t[1], t[3]);
|
||||
}
|
||||
else if (t[0] === 'domains' && t.length === 3 && t[2] === 'dmarc') {
|
||||
await domainDMARC(t[1]);
|
||||
}
|
||||
|
@ -875,6 +875,37 @@ const account = async (name: string) => {
|
||||
),
|
||||
),
|
||||
dom.br(),
|
||||
|
||||
dom.h2('Aliases/lists'),
|
||||
dom.table(
|
||||
dom.thead(
|
||||
dom.tr(
|
||||
dom.th('Alias address'),
|
||||
dom.th('Subscription address'),
|
||||
dom.th('Allowed senders', attr.title('Whether only members can send through the alias/list, or anyone.')),
|
||||
dom.th('Send as alias address', attr.title('If enabled, messages can be sent with the alias address in the message "From" header.')),
|
||||
dom.th('Members visible', attr.title('If enabled, members can see the addresses of other members.')),
|
||||
),
|
||||
),
|
||||
(config.Aliases || []).length === 0 ? dom.tr(dom.td(attr.colspan('6'), 'None')) : [],
|
||||
(config.Aliases || []).sort((a, b) => a.Alias.LocalpartStr < b.Alias.LocalpartStr ? -1 : (domainName(a.Alias.Domain) < domainName(b.Alias.Domain) ? -1 : 1)).map(a =>
|
||||
dom.tr(
|
||||
dom.td(dom.a(a.Alias.LocalpartStr, '@', domainName(a.Alias.Domain), attr.href('#domains/'+domainName(a.Alias.Domain)+'/alias/'+encodeURIComponent(a.Alias.LocalpartStr)))),
|
||||
dom.td(a.SubscriptionAddress),
|
||||
dom.td(a.Alias.PostPublic ? 'Anyone' : 'Members only'),
|
||||
dom.td(a.Alias.AllowMsgFrom ? 'Yes' : 'No'),
|
||||
dom.td(a.Alias.ListMembers ? 'Yes' : 'No'),
|
||||
dom.td(
|
||||
dom.clickbutton('Remove', async function click(e: MouseEvent) {
|
||||
await check(e.target! as HTMLButtonElement, client.AliasAddressesRemove(a.Alias.LocalpartStr, domainName(a.Alias.Domain), [a.SubscriptionAddress]))
|
||||
window.location.reload() // todo: reload less
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
dom.br(),
|
||||
|
||||
dom.h2('Settings'),
|
||||
dom.form(
|
||||
fieldsetSettings=dom.fieldset(
|
||||
@ -1009,7 +1040,7 @@ const formatDuration = (v: number, goDuration?: boolean) => {
|
||||
const domain = async (d: string) => {
|
||||
const end = new Date()
|
||||
const start = new Date(new Date().getTime() - 30*24*3600*1000)
|
||||
const [dmarcSummaries, tlsrptSummaries, localpartAccounts, dnsdomain, clientConfigs, accounts, domainConfig, transports] = await Promise.all([
|
||||
const [dmarcSummaries, tlsrptSummaries, [localpartAccounts, localpartAliases], dnsdomain, clientConfigs, accounts, domainConfig, transports] = await Promise.all([
|
||||
client.DMARCSummaries(start, end, d),
|
||||
client.TLSRPTSummaries(start, end, d),
|
||||
client.DomainLocalparts(d),
|
||||
@ -1025,6 +1056,10 @@ const domain = async (d: string) => {
|
||||
let addrLocalpart: HTMLInputElement
|
||||
let addrAccount: HTMLSelectElement
|
||||
|
||||
let aliasFieldset: HTMLFieldSetElement
|
||||
let aliasLocalpart: HTMLInputElement
|
||||
let aliasAddresses: HTMLTextAreaElement
|
||||
|
||||
let descrFieldset: HTMLFieldSetElement
|
||||
let descrText: HTMLInputElement
|
||||
|
||||
@ -1247,7 +1282,6 @@ const domain = async (d: string) => {
|
||||
),
|
||||
),
|
||||
dom.br(),
|
||||
|
||||
dom.h2('Add address'),
|
||||
addrForm=dom.form(
|
||||
async function submit(e: SubmitEvent) {
|
||||
@ -1278,6 +1312,64 @@ const domain = async (d: string) => {
|
||||
),
|
||||
dom.br(),
|
||||
|
||||
dom.h2('Aliases/lists'),
|
||||
dom.table(
|
||||
dom.thead(
|
||||
dom.tr(
|
||||
dom.th('Address'),
|
||||
dom.th('Allowed senders', attr.title('Whether only members can send through the alias/list, or anyone.')),
|
||||
dom.th('Send as alias address', attr.title('If enabled, messages can be sent with the alias address in the message "From" header.')),
|
||||
dom.th('Members visible', attr.title('If enabled, members can see the addresses of other members.')),
|
||||
),
|
||||
),
|
||||
Object.values(localpartAliases).length === 0 ? dom.tr(dom.td(attr.colspan('4'), 'None')) : [],
|
||||
Object.values(localpartAliases).sort((a, b) => a.LocalpartStr < b.LocalpartStr ? -1 : 1).map(a => {
|
||||
return dom.tr(
|
||||
dom.td(dom.a(a.LocalpartStr, attr.href('#domains/'+d+'/alias/'+encodeURIComponent(a.LocalpartStr)))),
|
||||
dom.td(a.PostPublic ? 'Anyone' : 'Members only'),
|
||||
dom.td(a.AllowMsgFrom ? 'Yes' : 'No'),
|
||||
dom.td(a.ListMembers ? 'Yes' : 'No'),
|
||||
)
|
||||
}),
|
||||
),
|
||||
dom.br(),
|
||||
dom.h2('Add alias'),
|
||||
dom.form(
|
||||
async function submit(e: SubmitEvent) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
const alias: api.Alias = {
|
||||
Addresses: aliasAddresses.value.split('\n').map(s => s.trim()).filter(s => !!s),
|
||||
PostPublic: false,
|
||||
ListMembers: false,
|
||||
AllowMsgFrom: false,
|
||||
// Ignored:
|
||||
LocalpartStr: '',
|
||||
Domain: dnsdomain,
|
||||
}
|
||||
await check(aliasFieldset, client.AliasAdd(aliasLocalpart.value, d, alias))
|
||||
window.location.hash = '#domains/'+d+'/alias/'+aliasLocalpart.value
|
||||
},
|
||||
aliasFieldset=dom.fieldset(
|
||||
style({display: 'flex', alignItems: 'flex-start', gap: '1em'}),
|
||||
dom.label(
|
||||
dom.div('Localpart', attr.title('The localpart is the part before the "@"-sign of an address.')),
|
||||
aliasLocalpart=dom.input(attr.required('')),
|
||||
'@', domainName(dnsdomain),
|
||||
' ',
|
||||
),
|
||||
dom.label(
|
||||
dom.div('Addresses', attr.title('One members address per line, full address of form localpart@domain. At least one address required.')),
|
||||
aliasAddresses=dom.textarea(attr.required(''), attr.rows('1'), function focus() { aliasAddresses.setAttribute('rows', '5') }),
|
||||
),
|
||||
dom.div(
|
||||
dom.div('\u00a0'),
|
||||
dom.submitbutton('Add alias', attr.title('Alias will be added and the config reloaded.')),
|
||||
),
|
||||
),
|
||||
),
|
||||
dom.br(),
|
||||
|
||||
RoutesEditor('domain-specific', transports, domainConfig.Routes || [], async (routes: api.Route[]) => await client.DomainRoutesSave(d, routes)),
|
||||
dom.br(),
|
||||
|
||||
@ -1680,6 +1772,122 @@ const domain = async (d: string) => {
|
||||
)
|
||||
}
|
||||
|
||||
const domainAlias = async (d: string, aliasLocalpart: string) => {
|
||||
const domain = await client.DomainConfig(d)
|
||||
const alias = (domain.Aliases || {})[aliasLocalpart]
|
||||
if (!alias) {
|
||||
throw new Error('alias not found')
|
||||
}
|
||||
|
||||
let aliasFieldset: HTMLFieldSetElement
|
||||
let postPublic: HTMLInputElement
|
||||
let listMembers: HTMLInputElement
|
||||
let allowMsgFrom: HTMLInputElement
|
||||
|
||||
let addFieldset: HTMLFieldSetElement
|
||||
let addAddress: HTMLTextAreaElement
|
||||
|
||||
let delFieldset: HTMLFieldSetElement
|
||||
|
||||
dom._kids(page,
|
||||
crumbs(
|
||||
crumblink('Mox Admin', '#'),
|
||||
crumblink('Domain ' + domainString(domain.Domain), '#domains/'+d),
|
||||
'Alias '+aliasLocalpart+'@'+domainName(domain.Domain),
|
||||
),
|
||||
|
||||
dom.h2('Alias'),
|
||||
dom.form(
|
||||
async function submit(e: SubmitEvent) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
check(aliasFieldset, client.AliasUpdate(aliasLocalpart, d, postPublic.checked, listMembers.checked, allowMsgFrom.checked))
|
||||
},
|
||||
aliasFieldset=dom.fieldset(
|
||||
style({display: 'flex', flexDirection: 'column', gap: '.5ex'}),
|
||||
dom.label(
|
||||
postPublic=dom.input(attr.type('checkbox'), alias.PostPublic ? attr.checked('') : []),
|
||||
' Public, anyone can post instead of only members',
|
||||
),
|
||||
dom.label(
|
||||
listMembers=dom.input(attr.type('checkbox'), alias.ListMembers ? attr.checked('') : []),
|
||||
' Members can list other members',
|
||||
),
|
||||
dom.label(
|
||||
allowMsgFrom=dom.input(attr.type('checkbox'), alias.AllowMsgFrom ? attr.checked('') : []),
|
||||
' Allow messages to use the alias address in the message From header',
|
||||
),
|
||||
dom.div(style({marginTop: '1ex'}), dom.submitbutton('Save')),
|
||||
),
|
||||
),
|
||||
dom.br(),
|
||||
|
||||
dom.h2('Members'),
|
||||
dom.table(
|
||||
dom.thead(
|
||||
dom.tr(
|
||||
dom.th('Address'),
|
||||
dom.th('Account'),
|
||||
dom.th(),
|
||||
),
|
||||
),
|
||||
dom.tbody(
|
||||
(alias.Addresses || []).map((address, index) => {
|
||||
const pa = (alias.ParsedAddresses || [])[index]
|
||||
return dom.tr(
|
||||
dom.td(address),
|
||||
dom.td(dom.a(pa.AccountName, attr.href('#accounts/'+pa.AccountName))),
|
||||
dom.td(
|
||||
dom.clickbutton('Remove', async function click(e: MouseEvent) {
|
||||
await check(e.target! as HTMLButtonElement, client.AliasAddressesRemove(aliasLocalpart, d, [address]))
|
||||
window.location.reload() // todo: reload less
|
||||
}),
|
||||
),
|
||||
)
|
||||
}),
|
||||
),
|
||||
dom.tfoot(
|
||||
dom.tr(
|
||||
dom.td(
|
||||
attr.colspan('3'),
|
||||
dom.form(
|
||||
async function submit(e: SubmitEvent) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
await check(addFieldset, client.AliasAddressesAdd(aliasLocalpart, d, addAddress.value.split('\n').map(s => s.trim()).filter(s => s)))
|
||||
window.location.reload() // todo: reload less
|
||||
},
|
||||
addFieldset=dom.fieldset(
|
||||
addAddress=dom.textarea(attr.required(''), attr.rows('1'), attr.placeholder('localpart@domain'), function focus() { addAddress.setAttribute('rows', '5') }), ' ',
|
||||
dom.submitbutton('Add', style({verticalAlign: 'top'})),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
dom.br(),
|
||||
|
||||
dom.h2('Danger'),
|
||||
dom.form(
|
||||
async function submit(e: SubmitEvent) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
||||
if (!confirm('Are you sure you want to remove this alias?')) {
|
||||
return
|
||||
}
|
||||
|
||||
await check(delFieldset, client.AliasRemove(aliasLocalpart, d))
|
||||
window.location.hash = '#domains/'+d
|
||||
},
|
||||
delFieldset=dom.fieldset(
|
||||
dom.div(dom.submitbutton('Remove alias')),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
const domainDNSRecords = async (d: string) => {
|
||||
const [records, dnsdomain] = await Promise.all([
|
||||
client.DomainRecords(d),
|
||||
@ -4846,6 +5054,8 @@ const init = async () => {
|
||||
await account(t[1])
|
||||
} else if (t[0] === 'domains' && t.length === 2) {
|
||||
await domain(t[1])
|
||||
} else if (t[0] === 'domains' && t.length === 4 && t[2] === 'alias') {
|
||||
await domainAlias(t[1], t[3])
|
||||
} else if (t[0] === 'domains' && t.length === 3 && t[2] === 'dmarc') {
|
||||
await domainDMARC(t[1])
|
||||
} else if (t[0] === 'domains' && t.length === 4 && t[2] === 'dmarc' && parseInt(t[3])) {
|
||||
|
@ -321,6 +321,44 @@ func TestAdmin(t *testing.T) {
|
||||
api.DomainDKIMRemove(ctxbg, "mox.example", "testsel")
|
||||
tneedErrorCode(t, "user:error", func() { api.DomainDKIMRemove(ctxbg, "mox.example", "testsel") }) // Already removed.
|
||||
tneedErrorCode(t, "user:error", func() { api.DomainDKIMRemove(ctxbg, "bogus.example", "testsel") })
|
||||
|
||||
// Aliases
|
||||
alias := config.Alias{Addresses: []string{"mjl@mox.example"}}
|
||||
api.AliasAdd(ctxbg, "support", "mox.example", alias)
|
||||
tneedErrorCode(t, "user:error", func() { api.AliasAdd(ctxbg, "support", "mox.example", alias) }) // Already present.
|
||||
tneedErrorCode(t, "user:error", func() { api.AliasAdd(ctxbg, "Support", "mox.example", alias) }) // Duplicate, canonical.
|
||||
tneedErrorCode(t, "user:error", func() { api.AliasAdd(ctxbg, "support", "bogus.example", alias) }) // Unknown domain.
|
||||
tneedErrorCode(t, "user:error", func() { api.AliasAdd(ctxbg, "support2", "mox.example", config.Alias{}) }) // No addresses.
|
||||
|
||||
api.AliasUpdate(ctxbg, "support", "mox.example", true, true, true)
|
||||
tneedErrorCode(t, "user:error", func() { api.AliasUpdate(ctxbg, "bogus", "mox.example", true, true, true) }) // Unknown alias localpart.
|
||||
tneedErrorCode(t, "user:error", func() { api.AliasUpdate(ctxbg, "support", "bogus.example", true, true, true) }) // Unknown alias domain.
|
||||
|
||||
tneedErrorCode(t, "user:error", func() {
|
||||
api.AliasAddressesAdd(ctxbg, "support", "mox.example", []string{"mjl2@mox.example", "mjl2@mox.example"})
|
||||
}) // Cannot add twice.
|
||||
api.AliasAddressesAdd(ctxbg, "support", "mox.example", []string{"mjl2@mox.example"})
|
||||
tneedErrorCode(t, "user:error", func() { api.AliasAddressesAdd(ctxbg, "support", "mox.example", []string{"mjl2@mox.example"}) }) // Already present.
|
||||
tneedErrorCode(t, "user:error", func() { api.AliasAddressesAdd(ctxbg, "support", "mox.example", []string{"bogus@mox.example"}) }) // Unknown dest localpart.
|
||||
tneedErrorCode(t, "user:error", func() { api.AliasAddressesAdd(ctxbg, "support", "mox.example", []string{"bogus@bogus.example"}) }) // Unknown dest domain.
|
||||
tneedErrorCode(t, "user:error", func() { api.AliasAddressesAdd(ctxbg, "support2", "mox.example", []string{"mjl@mox.example"}) }) // Unknown alias localpart.
|
||||
tneedErrorCode(t, "user:error", func() { api.AliasAddressesAdd(ctxbg, "support", "bogus.example", []string{"mjl@mox.example"}) }) // Unknown alias localpart.
|
||||
tneedErrorCode(t, "user:error", func() { api.AliasAddressesAdd(ctxbg, "support", "mox.example", []string{"support@mox.example"}) }) // Alias cannot be destination.
|
||||
|
||||
tneedErrorCode(t, "user:error", func() { api.AliasAddressesRemove(ctxbg, "support", "mox.example", []string{}) }) // Need at least 1 address.
|
||||
tneedErrorCode(t, "user:error", func() { api.AliasAddressesRemove(ctxbg, "support", "mox.example", []string{"bogus@mox.example"}) }) // Not a member.
|
||||
tneedErrorCode(t, "user:error", func() { api.AliasAddressesRemove(ctxbg, "support", "mox.example", []string{"bogus@bogus.example"}) }) // Not member, unknown domain.
|
||||
tneedErrorCode(t, "user:error", func() { api.AliasAddressesRemove(ctxbg, "support2", "mox.example", []string{"mjl@mox.example"}) }) // Unknown alias localpart.
|
||||
tneedErrorCode(t, "user:error", func() { api.AliasAddressesRemove(ctxbg, "support", "bogus.example", []string{"mjl@mox.example"}) }) // Unknown alias domain.
|
||||
tneedErrorCode(t, "user:error", func() {
|
||||
api.AliasAddressesRemove(ctxbg, "support", "mox.example", []string{"mjl@mox.example", "mjl2@mox.example"})
|
||||
}) // Cannot leave zero addresses.
|
||||
api.AliasAddressesRemove(ctxbg, "support", "mox.example", []string{"mjl@mox.example"})
|
||||
|
||||
api.AliasRemove(ctxbg, "support", "mox.example") // Restore.
|
||||
tneedErrorCode(t, "user:error", func() { api.AliasRemove(ctxbg, "support", "mox.example") }) // No longer exists.
|
||||
tneedErrorCode(t, "user:error", func() { api.AliasRemove(ctxbg, "support", "bogus.example") }) // Unknown alias domain.
|
||||
|
||||
}
|
||||
|
||||
func TestCheckDomain(t *testing.T) {
|
||||
|
@ -159,6 +159,13 @@
|
||||
"{}",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "localpartAliases",
|
||||
"Typewords": [
|
||||
"{}",
|
||||
"Alias"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -1898,6 +1905,139 @@
|
||||
}
|
||||
],
|
||||
"Returns": []
|
||||
},
|
||||
{
|
||||
"Name": "AliasAdd",
|
||||
"Docs": "",
|
||||
"Params": [
|
||||
{
|
||||
"Name": "aliaslp",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "domainName",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "alias",
|
||||
"Typewords": [
|
||||
"Alias"
|
||||
]
|
||||
}
|
||||
],
|
||||
"Returns": []
|
||||
},
|
||||
{
|
||||
"Name": "AliasUpdate",
|
||||
"Docs": "",
|
||||
"Params": [
|
||||
{
|
||||
"Name": "aliaslp",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "domainName",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "postPublic",
|
||||
"Typewords": [
|
||||
"bool"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "listMembers",
|
||||
"Typewords": [
|
||||
"bool"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "allowMsgFrom",
|
||||
"Typewords": [
|
||||
"bool"
|
||||
]
|
||||
}
|
||||
],
|
||||
"Returns": []
|
||||
},
|
||||
{
|
||||
"Name": "AliasRemove",
|
||||
"Docs": "",
|
||||
"Params": [
|
||||
{
|
||||
"Name": "aliaslp",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "domainName",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
}
|
||||
],
|
||||
"Returns": []
|
||||
},
|
||||
{
|
||||
"Name": "AliasAddressesAdd",
|
||||
"Docs": "",
|
||||
"Params": [
|
||||
{
|
||||
"Name": "aliaslp",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "domainName",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "addresses",
|
||||
"Typewords": [
|
||||
"[]",
|
||||
"string"
|
||||
]
|
||||
}
|
||||
],
|
||||
"Returns": []
|
||||
},
|
||||
{
|
||||
"Name": "AliasAddressesRemove",
|
||||
"Docs": "",
|
||||
"Params": [
|
||||
{
|
||||
"Name": "aliaslp",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "domainName",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "addresses",
|
||||
"Typewords": [
|
||||
"[]",
|
||||
"string"
|
||||
]
|
||||
}
|
||||
],
|
||||
"Returns": []
|
||||
}
|
||||
],
|
||||
"Sections": [],
|
||||
@ -3234,6 +3374,21 @@
|
||||
"[]",
|
||||
"Route"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Aliases",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"{}",
|
||||
"Alias"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Domain",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"Domain"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -3533,6 +3688,222 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Alias",
|
||||
"Docs": "",
|
||||
"Fields": [
|
||||
{
|
||||
"Name": "Addresses",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"[]",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "PostPublic",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"bool"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "ListMembers",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"bool"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "AllowMsgFrom",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"bool"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "LocalpartStr",
|
||||
"Docs": "In encoded form.",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Domain",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"Domain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "ParsedAddresses",
|
||||
"Docs": "Matches addresses.",
|
||||
"Typewords": [
|
||||
"[]",
|
||||
"AliasAddress"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "AliasAddress",
|
||||
"Docs": "",
|
||||
"Fields": [
|
||||
{
|
||||
"Name": "Address",
|
||||
"Docs": "Parsed address.",
|
||||
"Typewords": [
|
||||
"Address"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "AccountName",
|
||||
"Docs": "Looked up.",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Destination",
|
||||
"Docs": "Belonging to address.",
|
||||
"Typewords": [
|
||||
"Destination"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Address",
|
||||
"Docs": "Address is a parsed email address.",
|
||||
"Fields": [
|
||||
{
|
||||
"Name": "Localpart",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"Localpart"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Domain",
|
||||
"Docs": "todo: shouldn't we accept an ip address here too? and merge this type into smtp.Path.",
|
||||
"Typewords": [
|
||||
"Domain"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Destination",
|
||||
"Docs": "",
|
||||
"Fields": [
|
||||
{
|
||||
"Name": "Mailbox",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Rulesets",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"[]",
|
||||
"Ruleset"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "FullName",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Ruleset",
|
||||
"Docs": "",
|
||||
"Fields": [
|
||||
{
|
||||
"Name": "SMTPMailFromRegexp",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "MsgFromRegexp",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "VerifiedDomain",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "HeadersRegexp",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"{}",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "IsForward",
|
||||
"Docs": "todo: once we implement ARC, we can use dkim domains that we cannot verify but that the arc-verified forwarding mail server was able to verify.",
|
||||
"Typewords": [
|
||||
"bool"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "ListAllowDomain",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "AcceptRejectsToMailbox",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Mailbox",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Comment",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "VerifiedDNSDomain",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"Domain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "ListAllowDNSDomain",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"Domain"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Account",
|
||||
"Docs": "",
|
||||
@ -3682,6 +4053,14 @@
|
||||
"Typewords": [
|
||||
"Domain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Aliases",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"[]",
|
||||
"AddressAlias"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -3733,118 +4112,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Destination",
|
||||
"Docs": "",
|
||||
"Fields": [
|
||||
{
|
||||
"Name": "Mailbox",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Rulesets",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"[]",
|
||||
"Ruleset"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "FullName",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Ruleset",
|
||||
"Docs": "",
|
||||
"Fields": [
|
||||
{
|
||||
"Name": "SMTPMailFromRegexp",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "MsgFromRegexp",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "VerifiedDomain",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "HeadersRegexp",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"{}",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "IsForward",
|
||||
"Docs": "todo: once we implement ARC, we can use dkim domains that we cannot verify but that the arc-verified forwarding mail server was able to verify.",
|
||||
"Typewords": [
|
||||
"bool"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "ListAllowDomain",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "AcceptRejectsToMailbox",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Mailbox",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Comment",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "VerifiedDNSDomain",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"Domain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "ListAllowDNSDomain",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"Domain"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "SubjectPass",
|
||||
"Docs": "",
|
||||
@ -3954,6 +4221,34 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "AddressAlias",
|
||||
"Docs": "",
|
||||
"Fields": [
|
||||
{
|
||||
"Name": "SubscriptionAddress",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Alias",
|
||||
"Docs": "Without members.",
|
||||
"Typewords": [
|
||||
"Alias"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "MemberAddresses",
|
||||
"Docs": "Only if allowed to see.",
|
||||
"Typewords": [
|
||||
"[]",
|
||||
"string"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "PolicyRecord",
|
||||
"Docs": "PolicyRecord is a cached policy or absence of a policy.",
|
||||
|
155
webadmin/api.ts
155
webadmin/api.ts
@ -275,6 +275,8 @@ export interface ConfigDomain {
|
||||
MTASTS?: MTASTS | null
|
||||
TLSRPT?: TLSRPT | null
|
||||
Routes?: Route[] | null
|
||||
Aliases?: { [key: string]: Alias }
|
||||
Domain: Domain
|
||||
}
|
||||
|
||||
export interface DKIM {
|
||||
@ -333,38 +335,26 @@ export interface Route {
|
||||
ToDomainASCII?: string[] | null
|
||||
}
|
||||
|
||||
export interface Account {
|
||||
OutgoingWebhook?: OutgoingWebhook | null
|
||||
IncomingWebhook?: IncomingWebhook | null
|
||||
FromIDLoginAddresses?: string[] | null
|
||||
KeepRetiredMessagePeriod: number
|
||||
KeepRetiredWebhookPeriod: number
|
||||
Domain: string
|
||||
Description: string
|
||||
FullName: string
|
||||
Destinations?: { [key: string]: Destination }
|
||||
SubjectPass: SubjectPass
|
||||
QuotaMessageSize: number
|
||||
RejectsMailbox: string
|
||||
KeepRejects: boolean
|
||||
AutomaticJunkFlags: AutomaticJunkFlags
|
||||
JunkFilter?: JunkFilter | null // todo: sane defaults for junkfilter
|
||||
MaxOutgoingMessagesPerDay: number
|
||||
MaxFirstTimeRecipientsPerDay: number
|
||||
NoFirstTimeSenderDelay: boolean
|
||||
Routes?: Route[] | null
|
||||
DNSDomain: Domain // Parsed form of Domain.
|
||||
export interface Alias {
|
||||
Addresses?: string[] | null
|
||||
PostPublic: boolean
|
||||
ListMembers: boolean
|
||||
AllowMsgFrom: boolean
|
||||
LocalpartStr: string // In encoded form.
|
||||
Domain: Domain
|
||||
ParsedAddresses?: AliasAddress[] | null // Matches addresses.
|
||||
}
|
||||
|
||||
export interface OutgoingWebhook {
|
||||
URL: string
|
||||
Authorization: string
|
||||
Events?: string[] | null
|
||||
export interface AliasAddress {
|
||||
Address: Address // Parsed address.
|
||||
AccountName: string // Looked up.
|
||||
Destination: Destination // Belonging to address.
|
||||
}
|
||||
|
||||
export interface IncomingWebhook {
|
||||
URL: string
|
||||
Authorization: string
|
||||
// Address is a parsed email address.
|
||||
export interface Address {
|
||||
Localpart: Localpart
|
||||
Domain: Domain // todo: shouldn't we accept an ip address here too? and merge this type into smtp.Path.
|
||||
}
|
||||
|
||||
export interface Destination {
|
||||
@ -387,6 +377,41 @@ export interface Ruleset {
|
||||
ListAllowDNSDomain: Domain
|
||||
}
|
||||
|
||||
export interface Account {
|
||||
OutgoingWebhook?: OutgoingWebhook | null
|
||||
IncomingWebhook?: IncomingWebhook | null
|
||||
FromIDLoginAddresses?: string[] | null
|
||||
KeepRetiredMessagePeriod: number
|
||||
KeepRetiredWebhookPeriod: number
|
||||
Domain: string
|
||||
Description: string
|
||||
FullName: string
|
||||
Destinations?: { [key: string]: Destination }
|
||||
SubjectPass: SubjectPass
|
||||
QuotaMessageSize: number
|
||||
RejectsMailbox: string
|
||||
KeepRejects: boolean
|
||||
AutomaticJunkFlags: AutomaticJunkFlags
|
||||
JunkFilter?: JunkFilter | null // todo: sane defaults for junkfilter
|
||||
MaxOutgoingMessagesPerDay: number
|
||||
MaxFirstTimeRecipientsPerDay: number
|
||||
NoFirstTimeSenderDelay: boolean
|
||||
Routes?: Route[] | null
|
||||
DNSDomain: Domain // Parsed form of Domain.
|
||||
Aliases?: AddressAlias[] | null
|
||||
}
|
||||
|
||||
export interface OutgoingWebhook {
|
||||
URL: string
|
||||
Authorization: string
|
||||
Events?: string[] | null
|
||||
}
|
||||
|
||||
export interface IncomingWebhook {
|
||||
URL: string
|
||||
Authorization: string
|
||||
}
|
||||
|
||||
export interface SubjectPass {
|
||||
Period: number // todo: have a reasonable default for this?
|
||||
}
|
||||
@ -409,6 +434,12 @@ export interface JunkFilter {
|
||||
RareWords: number
|
||||
}
|
||||
|
||||
export interface AddressAlias {
|
||||
SubscriptionAddress: string
|
||||
Alias: Alias // Without members.
|
||||
MemberAddresses?: string[] | null // Only if allowed to see.
|
||||
}
|
||||
|
||||
// PolicyRecord is a cached policy or absence of a policy.
|
||||
export interface PolicyRecord {
|
||||
Domain: string // Domain name, with unicode characters.
|
||||
@ -1146,7 +1177,7 @@ export enum SPFResult {
|
||||
// be an IPv4 address.
|
||||
export type IP = string
|
||||
|
||||
export const structTypes: {[typename: string]: boolean} = {"Account":true,"AuthResults":true,"AutoconfCheckResult":true,"AutodiscoverCheckResult":true,"AutodiscoverSRV":true,"AutomaticJunkFlags":true,"Canonicalization":true,"CheckResult":true,"ClientConfigs":true,"ClientConfigsEntry":true,"ConfigDomain":true,"DANECheckResult":true,"DKIM":true,"DKIMAuthResult":true,"DKIMCheckResult":true,"DKIMRecord":true,"DMARC":true,"DMARCCheckResult":true,"DMARCRecord":true,"DMARCSummary":true,"DNSSECResult":true,"DateRange":true,"Destination":true,"Directive":true,"Domain":true,"DomainFeedback":true,"Dynamic":true,"Evaluation":true,"EvaluationStat":true,"Extension":true,"FailureDetails":true,"Filter":true,"HoldRule":true,"Hook":true,"HookFilter":true,"HookResult":true,"HookRetired":true,"HookRetiredFilter":true,"HookRetiredSort":true,"HookSort":true,"IPDomain":true,"IPRevCheckResult":true,"Identifiers":true,"IncomingWebhook":true,"JunkFilter":true,"MTASTS":true,"MTASTSCheckResult":true,"MTASTSRecord":true,"MX":true,"MXCheckResult":true,"Modifier":true,"Msg":true,"MsgResult":true,"MsgRetired":true,"OutgoingWebhook":true,"Pair":true,"Policy":true,"PolicyEvaluated":true,"PolicyOverrideReason":true,"PolicyPublished":true,"PolicyRecord":true,"Record":true,"Report":true,"ReportMetadata":true,"ReportRecord":true,"Result":true,"ResultPolicy":true,"RetiredFilter":true,"RetiredSort":true,"Reverse":true,"Route":true,"Row":true,"Ruleset":true,"SMTPAuth":true,"SPFAuthResult":true,"SPFCheckResult":true,"SPFRecord":true,"SRV":true,"SRVConfCheckResult":true,"STSMX":true,"Selector":true,"Sort":true,"SubjectPass":true,"Summary":true,"SuppressAddress":true,"TLSCheckResult":true,"TLSRPT":true,"TLSRPTCheckResult":true,"TLSRPTDateRange":true,"TLSRPTRecord":true,"TLSRPTSummary":true,"TLSRPTSuppressAddress":true,"TLSReportRecord":true,"TLSResult":true,"Transport":true,"TransportDirect":true,"TransportSMTP":true,"TransportSocks":true,"URI":true,"WebForward":true,"WebHandler":true,"WebRedirect":true,"WebStatic":true,"WebserverConfig":true}
|
||||
export const structTypes: {[typename: string]: boolean} = {"Account":true,"Address":true,"AddressAlias":true,"Alias":true,"AliasAddress":true,"AuthResults":true,"AutoconfCheckResult":true,"AutodiscoverCheckResult":true,"AutodiscoverSRV":true,"AutomaticJunkFlags":true,"Canonicalization":true,"CheckResult":true,"ClientConfigs":true,"ClientConfigsEntry":true,"ConfigDomain":true,"DANECheckResult":true,"DKIM":true,"DKIMAuthResult":true,"DKIMCheckResult":true,"DKIMRecord":true,"DMARC":true,"DMARCCheckResult":true,"DMARCRecord":true,"DMARCSummary":true,"DNSSECResult":true,"DateRange":true,"Destination":true,"Directive":true,"Domain":true,"DomainFeedback":true,"Dynamic":true,"Evaluation":true,"EvaluationStat":true,"Extension":true,"FailureDetails":true,"Filter":true,"HoldRule":true,"Hook":true,"HookFilter":true,"HookResult":true,"HookRetired":true,"HookRetiredFilter":true,"HookRetiredSort":true,"HookSort":true,"IPDomain":true,"IPRevCheckResult":true,"Identifiers":true,"IncomingWebhook":true,"JunkFilter":true,"MTASTS":true,"MTASTSCheckResult":true,"MTASTSRecord":true,"MX":true,"MXCheckResult":true,"Modifier":true,"Msg":true,"MsgResult":true,"MsgRetired":true,"OutgoingWebhook":true,"Pair":true,"Policy":true,"PolicyEvaluated":true,"PolicyOverrideReason":true,"PolicyPublished":true,"PolicyRecord":true,"Record":true,"Report":true,"ReportMetadata":true,"ReportRecord":true,"Result":true,"ResultPolicy":true,"RetiredFilter":true,"RetiredSort":true,"Reverse":true,"Route":true,"Row":true,"Ruleset":true,"SMTPAuth":true,"SPFAuthResult":true,"SPFCheckResult":true,"SPFRecord":true,"SRV":true,"SRVConfCheckResult":true,"STSMX":true,"Selector":true,"Sort":true,"SubjectPass":true,"Summary":true,"SuppressAddress":true,"TLSCheckResult":true,"TLSRPT":true,"TLSRPTCheckResult":true,"TLSRPTDateRange":true,"TLSRPTRecord":true,"TLSRPTSummary":true,"TLSRPTSuppressAddress":true,"TLSReportRecord":true,"TLSResult":true,"Transport":true,"TransportDirect":true,"TransportSMTP":true,"TransportSocks":true,"URI":true,"WebForward":true,"WebHandler":true,"WebRedirect":true,"WebStatic":true,"WebserverConfig":true}
|
||||
export const stringsTypes: {[typename: string]: boolean} = {"Align":true,"Alignment":true,"CSRFToken":true,"DKIMResult":true,"DMARCPolicy":true,"DMARCResult":true,"Disposition":true,"IP":true,"Localpart":true,"Mode":true,"PolicyOverride":true,"PolicyType":true,"RUA":true,"ResultType":true,"SPFDomainScope":true,"SPFResult":true}
|
||||
export const intsTypes: {[typename: string]: boolean} = {}
|
||||
export const types: TypenameMap = {
|
||||
@ -1181,7 +1212,7 @@ export const types: TypenameMap = {
|
||||
"AutoconfCheckResult": {"Name":"AutoconfCheckResult","Docs":"","Fields":[{"Name":"ClientSettingsDomainIPs","Docs":"","Typewords":["[]","string"]},{"Name":"IPs","Docs":"","Typewords":["[]","string"]},{"Name":"Errors","Docs":"","Typewords":["[]","string"]},{"Name":"Warnings","Docs":"","Typewords":["[]","string"]},{"Name":"Instructions","Docs":"","Typewords":["[]","string"]}]},
|
||||
"AutodiscoverCheckResult": {"Name":"AutodiscoverCheckResult","Docs":"","Fields":[{"Name":"Records","Docs":"","Typewords":["[]","AutodiscoverSRV"]},{"Name":"Errors","Docs":"","Typewords":["[]","string"]},{"Name":"Warnings","Docs":"","Typewords":["[]","string"]},{"Name":"Instructions","Docs":"","Typewords":["[]","string"]}]},
|
||||
"AutodiscoverSRV": {"Name":"AutodiscoverSRV","Docs":"","Fields":[{"Name":"Target","Docs":"","Typewords":["string"]},{"Name":"Port","Docs":"","Typewords":["uint16"]},{"Name":"Priority","Docs":"","Typewords":["uint16"]},{"Name":"Weight","Docs":"","Typewords":["uint16"]},{"Name":"IPs","Docs":"","Typewords":["[]","string"]}]},
|
||||
"ConfigDomain": {"Name":"ConfigDomain","Docs":"","Fields":[{"Name":"Description","Docs":"","Typewords":["string"]},{"Name":"ClientSettingsDomain","Docs":"","Typewords":["string"]},{"Name":"LocalpartCatchallSeparator","Docs":"","Typewords":["string"]},{"Name":"LocalpartCaseSensitive","Docs":"","Typewords":["bool"]},{"Name":"DKIM","Docs":"","Typewords":["DKIM"]},{"Name":"DMARC","Docs":"","Typewords":["nullable","DMARC"]},{"Name":"MTASTS","Docs":"","Typewords":["nullable","MTASTS"]},{"Name":"TLSRPT","Docs":"","Typewords":["nullable","TLSRPT"]},{"Name":"Routes","Docs":"","Typewords":["[]","Route"]}]},
|
||||
"ConfigDomain": {"Name":"ConfigDomain","Docs":"","Fields":[{"Name":"Description","Docs":"","Typewords":["string"]},{"Name":"ClientSettingsDomain","Docs":"","Typewords":["string"]},{"Name":"LocalpartCatchallSeparator","Docs":"","Typewords":["string"]},{"Name":"LocalpartCaseSensitive","Docs":"","Typewords":["bool"]},{"Name":"DKIM","Docs":"","Typewords":["DKIM"]},{"Name":"DMARC","Docs":"","Typewords":["nullable","DMARC"]},{"Name":"MTASTS","Docs":"","Typewords":["nullable","MTASTS"]},{"Name":"TLSRPT","Docs":"","Typewords":["nullable","TLSRPT"]},{"Name":"Routes","Docs":"","Typewords":["[]","Route"]},{"Name":"Aliases","Docs":"","Typewords":["{}","Alias"]},{"Name":"Domain","Docs":"","Typewords":["Domain"]}]},
|
||||
"DKIM": {"Name":"DKIM","Docs":"","Fields":[{"Name":"Selectors","Docs":"","Typewords":["{}","Selector"]},{"Name":"Sign","Docs":"","Typewords":["[]","string"]}]},
|
||||
"Selector": {"Name":"Selector","Docs":"","Fields":[{"Name":"Hash","Docs":"","Typewords":["string"]},{"Name":"HashEffective","Docs":"","Typewords":["string"]},{"Name":"Canonicalization","Docs":"","Typewords":["Canonicalization"]},{"Name":"Headers","Docs":"","Typewords":["[]","string"]},{"Name":"HeadersEffective","Docs":"","Typewords":["[]","string"]},{"Name":"DontSealHeaders","Docs":"","Typewords":["bool"]},{"Name":"Expiration","Docs":"","Typewords":["string"]},{"Name":"PrivateKeyFile","Docs":"","Typewords":["string"]},{"Name":"Algorithm","Docs":"","Typewords":["string"]}]},
|
||||
"Canonicalization": {"Name":"Canonicalization","Docs":"","Fields":[{"Name":"HeaderRelaxed","Docs":"","Typewords":["bool"]},{"Name":"BodyRelaxed","Docs":"","Typewords":["bool"]}]},
|
||||
@ -1189,14 +1220,18 @@ export const types: TypenameMap = {
|
||||
"MTASTS": {"Name":"MTASTS","Docs":"","Fields":[{"Name":"PolicyID","Docs":"","Typewords":["string"]},{"Name":"Mode","Docs":"","Typewords":["Mode"]},{"Name":"MaxAge","Docs":"","Typewords":["int64"]},{"Name":"MX","Docs":"","Typewords":["[]","string"]}]},
|
||||
"TLSRPT": {"Name":"TLSRPT","Docs":"","Fields":[{"Name":"Localpart","Docs":"","Typewords":["string"]},{"Name":"Domain","Docs":"","Typewords":["string"]},{"Name":"Account","Docs":"","Typewords":["string"]},{"Name":"Mailbox","Docs":"","Typewords":["string"]},{"Name":"ParsedLocalpart","Docs":"","Typewords":["Localpart"]},{"Name":"DNSDomain","Docs":"","Typewords":["Domain"]}]},
|
||||
"Route": {"Name":"Route","Docs":"","Fields":[{"Name":"FromDomain","Docs":"","Typewords":["[]","string"]},{"Name":"ToDomain","Docs":"","Typewords":["[]","string"]},{"Name":"MinimumAttempts","Docs":"","Typewords":["int32"]},{"Name":"Transport","Docs":"","Typewords":["string"]},{"Name":"FromDomainASCII","Docs":"","Typewords":["[]","string"]},{"Name":"ToDomainASCII","Docs":"","Typewords":["[]","string"]}]},
|
||||
"Account": {"Name":"Account","Docs":"","Fields":[{"Name":"OutgoingWebhook","Docs":"","Typewords":["nullable","OutgoingWebhook"]},{"Name":"IncomingWebhook","Docs":"","Typewords":["nullable","IncomingWebhook"]},{"Name":"FromIDLoginAddresses","Docs":"","Typewords":["[]","string"]},{"Name":"KeepRetiredMessagePeriod","Docs":"","Typewords":["int64"]},{"Name":"KeepRetiredWebhookPeriod","Docs":"","Typewords":["int64"]},{"Name":"Domain","Docs":"","Typewords":["string"]},{"Name":"Description","Docs":"","Typewords":["string"]},{"Name":"FullName","Docs":"","Typewords":["string"]},{"Name":"Destinations","Docs":"","Typewords":["{}","Destination"]},{"Name":"SubjectPass","Docs":"","Typewords":["SubjectPass"]},{"Name":"QuotaMessageSize","Docs":"","Typewords":["int64"]},{"Name":"RejectsMailbox","Docs":"","Typewords":["string"]},{"Name":"KeepRejects","Docs":"","Typewords":["bool"]},{"Name":"AutomaticJunkFlags","Docs":"","Typewords":["AutomaticJunkFlags"]},{"Name":"JunkFilter","Docs":"","Typewords":["nullable","JunkFilter"]},{"Name":"MaxOutgoingMessagesPerDay","Docs":"","Typewords":["int32"]},{"Name":"MaxFirstTimeRecipientsPerDay","Docs":"","Typewords":["int32"]},{"Name":"NoFirstTimeSenderDelay","Docs":"","Typewords":["bool"]},{"Name":"Routes","Docs":"","Typewords":["[]","Route"]},{"Name":"DNSDomain","Docs":"","Typewords":["Domain"]}]},
|
||||
"OutgoingWebhook": {"Name":"OutgoingWebhook","Docs":"","Fields":[{"Name":"URL","Docs":"","Typewords":["string"]},{"Name":"Authorization","Docs":"","Typewords":["string"]},{"Name":"Events","Docs":"","Typewords":["[]","string"]}]},
|
||||
"IncomingWebhook": {"Name":"IncomingWebhook","Docs":"","Fields":[{"Name":"URL","Docs":"","Typewords":["string"]},{"Name":"Authorization","Docs":"","Typewords":["string"]}]},
|
||||
"Alias": {"Name":"Alias","Docs":"","Fields":[{"Name":"Addresses","Docs":"","Typewords":["[]","string"]},{"Name":"PostPublic","Docs":"","Typewords":["bool"]},{"Name":"ListMembers","Docs":"","Typewords":["bool"]},{"Name":"AllowMsgFrom","Docs":"","Typewords":["bool"]},{"Name":"LocalpartStr","Docs":"","Typewords":["string"]},{"Name":"Domain","Docs":"","Typewords":["Domain"]},{"Name":"ParsedAddresses","Docs":"","Typewords":["[]","AliasAddress"]}]},
|
||||
"AliasAddress": {"Name":"AliasAddress","Docs":"","Fields":[{"Name":"Address","Docs":"","Typewords":["Address"]},{"Name":"AccountName","Docs":"","Typewords":["string"]},{"Name":"Destination","Docs":"","Typewords":["Destination"]}]},
|
||||
"Address": {"Name":"Address","Docs":"","Fields":[{"Name":"Localpart","Docs":"","Typewords":["Localpart"]},{"Name":"Domain","Docs":"","Typewords":["Domain"]}]},
|
||||
"Destination": {"Name":"Destination","Docs":"","Fields":[{"Name":"Mailbox","Docs":"","Typewords":["string"]},{"Name":"Rulesets","Docs":"","Typewords":["[]","Ruleset"]},{"Name":"FullName","Docs":"","Typewords":["string"]}]},
|
||||
"Ruleset": {"Name":"Ruleset","Docs":"","Fields":[{"Name":"SMTPMailFromRegexp","Docs":"","Typewords":["string"]},{"Name":"MsgFromRegexp","Docs":"","Typewords":["string"]},{"Name":"VerifiedDomain","Docs":"","Typewords":["string"]},{"Name":"HeadersRegexp","Docs":"","Typewords":["{}","string"]},{"Name":"IsForward","Docs":"","Typewords":["bool"]},{"Name":"ListAllowDomain","Docs":"","Typewords":["string"]},{"Name":"AcceptRejectsToMailbox","Docs":"","Typewords":["string"]},{"Name":"Mailbox","Docs":"","Typewords":["string"]},{"Name":"Comment","Docs":"","Typewords":["string"]},{"Name":"VerifiedDNSDomain","Docs":"","Typewords":["Domain"]},{"Name":"ListAllowDNSDomain","Docs":"","Typewords":["Domain"]}]},
|
||||
"Account": {"Name":"Account","Docs":"","Fields":[{"Name":"OutgoingWebhook","Docs":"","Typewords":["nullable","OutgoingWebhook"]},{"Name":"IncomingWebhook","Docs":"","Typewords":["nullable","IncomingWebhook"]},{"Name":"FromIDLoginAddresses","Docs":"","Typewords":["[]","string"]},{"Name":"KeepRetiredMessagePeriod","Docs":"","Typewords":["int64"]},{"Name":"KeepRetiredWebhookPeriod","Docs":"","Typewords":["int64"]},{"Name":"Domain","Docs":"","Typewords":["string"]},{"Name":"Description","Docs":"","Typewords":["string"]},{"Name":"FullName","Docs":"","Typewords":["string"]},{"Name":"Destinations","Docs":"","Typewords":["{}","Destination"]},{"Name":"SubjectPass","Docs":"","Typewords":["SubjectPass"]},{"Name":"QuotaMessageSize","Docs":"","Typewords":["int64"]},{"Name":"RejectsMailbox","Docs":"","Typewords":["string"]},{"Name":"KeepRejects","Docs":"","Typewords":["bool"]},{"Name":"AutomaticJunkFlags","Docs":"","Typewords":["AutomaticJunkFlags"]},{"Name":"JunkFilter","Docs":"","Typewords":["nullable","JunkFilter"]},{"Name":"MaxOutgoingMessagesPerDay","Docs":"","Typewords":["int32"]},{"Name":"MaxFirstTimeRecipientsPerDay","Docs":"","Typewords":["int32"]},{"Name":"NoFirstTimeSenderDelay","Docs":"","Typewords":["bool"]},{"Name":"Routes","Docs":"","Typewords":["[]","Route"]},{"Name":"DNSDomain","Docs":"","Typewords":["Domain"]},{"Name":"Aliases","Docs":"","Typewords":["[]","AddressAlias"]}]},
|
||||
"OutgoingWebhook": {"Name":"OutgoingWebhook","Docs":"","Fields":[{"Name":"URL","Docs":"","Typewords":["string"]},{"Name":"Authorization","Docs":"","Typewords":["string"]},{"Name":"Events","Docs":"","Typewords":["[]","string"]}]},
|
||||
"IncomingWebhook": {"Name":"IncomingWebhook","Docs":"","Fields":[{"Name":"URL","Docs":"","Typewords":["string"]},{"Name":"Authorization","Docs":"","Typewords":["string"]}]},
|
||||
"SubjectPass": {"Name":"SubjectPass","Docs":"","Fields":[{"Name":"Period","Docs":"","Typewords":["int64"]}]},
|
||||
"AutomaticJunkFlags": {"Name":"AutomaticJunkFlags","Docs":"","Fields":[{"Name":"Enabled","Docs":"","Typewords":["bool"]},{"Name":"JunkMailboxRegexp","Docs":"","Typewords":["string"]},{"Name":"NeutralMailboxRegexp","Docs":"","Typewords":["string"]},{"Name":"NotJunkMailboxRegexp","Docs":"","Typewords":["string"]}]},
|
||||
"JunkFilter": {"Name":"JunkFilter","Docs":"","Fields":[{"Name":"Threshold","Docs":"","Typewords":["float64"]},{"Name":"Onegrams","Docs":"","Typewords":["bool"]},{"Name":"Twograms","Docs":"","Typewords":["bool"]},{"Name":"Threegrams","Docs":"","Typewords":["bool"]},{"Name":"MaxPower","Docs":"","Typewords":["float64"]},{"Name":"TopWords","Docs":"","Typewords":["int32"]},{"Name":"IgnoreWords","Docs":"","Typewords":["float64"]},{"Name":"RareWords","Docs":"","Typewords":["int32"]}]},
|
||||
"AddressAlias": {"Name":"AddressAlias","Docs":"","Fields":[{"Name":"SubscriptionAddress","Docs":"","Typewords":["string"]},{"Name":"Alias","Docs":"","Typewords":["Alias"]},{"Name":"MemberAddresses","Docs":"","Typewords":["[]","string"]}]},
|
||||
"PolicyRecord": {"Name":"PolicyRecord","Docs":"","Fields":[{"Name":"Domain","Docs":"","Typewords":["string"]},{"Name":"Inserted","Docs":"","Typewords":["timestamp"]},{"Name":"ValidEnd","Docs":"","Typewords":["timestamp"]},{"Name":"LastUpdate","Docs":"","Typewords":["timestamp"]},{"Name":"LastUse","Docs":"","Typewords":["timestamp"]},{"Name":"Backoff","Docs":"","Typewords":["bool"]},{"Name":"RecordID","Docs":"","Typewords":["string"]},{"Name":"Version","Docs":"","Typewords":["string"]},{"Name":"Mode","Docs":"","Typewords":["Mode"]},{"Name":"MX","Docs":"","Typewords":["[]","STSMX"]},{"Name":"MaxAgeSeconds","Docs":"","Typewords":["int32"]},{"Name":"Extensions","Docs":"","Typewords":["[]","Pair"]},{"Name":"PolicyText","Docs":"","Typewords":["string"]}]},
|
||||
"TLSReportRecord": {"Name":"TLSReportRecord","Docs":"","Fields":[{"Name":"ID","Docs":"","Typewords":["int64"]},{"Name":"Domain","Docs":"","Typewords":["string"]},{"Name":"FromDomain","Docs":"","Typewords":["string"]},{"Name":"MailFrom","Docs":"","Typewords":["string"]},{"Name":"HostReport","Docs":"","Typewords":["bool"]},{"Name":"Report","Docs":"","Typewords":["Report"]}]},
|
||||
"Report": {"Name":"Report","Docs":"","Fields":[{"Name":"OrganizationName","Docs":"","Typewords":["string"]},{"Name":"DateRange","Docs":"","Typewords":["TLSRPTDateRange"]},{"Name":"ContactInfo","Docs":"","Typewords":["string"]},{"Name":"ReportID","Docs":"","Typewords":["string"]},{"Name":"Policies","Docs":"","Typewords":["[]","Result"]}]},
|
||||
@ -1312,14 +1347,18 @@ export const parser = {
|
||||
MTASTS: (v: any) => parse("MTASTS", v) as MTASTS,
|
||||
TLSRPT: (v: any) => parse("TLSRPT", v) as TLSRPT,
|
||||
Route: (v: any) => parse("Route", v) as Route,
|
||||
Alias: (v: any) => parse("Alias", v) as Alias,
|
||||
AliasAddress: (v: any) => parse("AliasAddress", v) as AliasAddress,
|
||||
Address: (v: any) => parse("Address", v) as Address,
|
||||
Destination: (v: any) => parse("Destination", v) as Destination,
|
||||
Ruleset: (v: any) => parse("Ruleset", v) as Ruleset,
|
||||
Account: (v: any) => parse("Account", v) as Account,
|
||||
OutgoingWebhook: (v: any) => parse("OutgoingWebhook", v) as OutgoingWebhook,
|
||||
IncomingWebhook: (v: any) => parse("IncomingWebhook", v) as IncomingWebhook,
|
||||
Destination: (v: any) => parse("Destination", v) as Destination,
|
||||
Ruleset: (v: any) => parse("Ruleset", v) as Ruleset,
|
||||
SubjectPass: (v: any) => parse("SubjectPass", v) as SubjectPass,
|
||||
AutomaticJunkFlags: (v: any) => parse("AutomaticJunkFlags", v) as AutomaticJunkFlags,
|
||||
JunkFilter: (v: any) => parse("JunkFilter", v) as JunkFilter,
|
||||
AddressAlias: (v: any) => parse("AddressAlias", v) as AddressAlias,
|
||||
PolicyRecord: (v: any) => parse("PolicyRecord", v) as PolicyRecord,
|
||||
TLSReportRecord: (v: any) => parse("TLSReportRecord", v) as TLSReportRecord,
|
||||
Report: (v: any) => parse("Report", v) as Report,
|
||||
@ -1501,12 +1540,12 @@ export class Client {
|
||||
}
|
||||
|
||||
// DomainLocalparts returns the encoded localparts and accounts configured in domain.
|
||||
async DomainLocalparts(domain: string): Promise<{ [key: string]: string }> {
|
||||
async DomainLocalparts(domain: string): Promise<[{ [key: string]: string }, { [key: string]: Alias }]> {
|
||||
const fn: string = "DomainLocalparts"
|
||||
const paramTypes: string[][] = [["string"]]
|
||||
const returnTypes: string[][] = [["{}","string"]]
|
||||
const returnTypes: string[][] = [["{}","string"],["{}","Alias"]]
|
||||
const params: any[] = [domain]
|
||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as { [key: string]: string }
|
||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as [{ [key: string]: string }, { [key: string]: Alias }]
|
||||
}
|
||||
|
||||
// Accounts returns the names of all configured accounts.
|
||||
@ -2253,6 +2292,46 @@ export class Client {
|
||||
const params: any[] = [domainName, selectors, sign]
|
||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
|
||||
}
|
||||
|
||||
async AliasAdd(aliaslp: string, domainName: string, alias: Alias): Promise<void> {
|
||||
const fn: string = "AliasAdd"
|
||||
const paramTypes: string[][] = [["string"],["string"],["Alias"]]
|
||||
const returnTypes: string[][] = []
|
||||
const params: any[] = [aliaslp, domainName, alias]
|
||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
|
||||
}
|
||||
|
||||
async AliasUpdate(aliaslp: string, domainName: string, postPublic: boolean, listMembers: boolean, allowMsgFrom: boolean): Promise<void> {
|
||||
const fn: string = "AliasUpdate"
|
||||
const paramTypes: string[][] = [["string"],["string"],["bool"],["bool"],["bool"]]
|
||||
const returnTypes: string[][] = []
|
||||
const params: any[] = [aliaslp, domainName, postPublic, listMembers, allowMsgFrom]
|
||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
|
||||
}
|
||||
|
||||
async AliasRemove(aliaslp: string, domainName: string): Promise<void> {
|
||||
const fn: string = "AliasRemove"
|
||||
const paramTypes: string[][] = [["string"],["string"]]
|
||||
const returnTypes: string[][] = []
|
||||
const params: any[] = [aliaslp, domainName]
|
||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
|
||||
}
|
||||
|
||||
async AliasAddressesAdd(aliaslp: string, domainName: string, addresses: string[] | null): Promise<void> {
|
||||
const fn: string = "AliasAddressesAdd"
|
||||
const paramTypes: string[][] = [["string"],["string"],["[]","string"]]
|
||||
const returnTypes: string[][] = []
|
||||
const params: any[] = [aliaslp, domainName, addresses]
|
||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
|
||||
}
|
||||
|
||||
async AliasAddressesRemove(aliaslp: string, domainName: string, addresses: string[] | null): Promise<void> {
|
||||
const fn: string = "AliasAddressesRemove"
|
||||
const paramTypes: string[][] = [["string"],["string"],["[]","string"]]
|
||||
const returnTypes: string[][] = []
|
||||
const params: any[] = [aliaslp, domainName, addresses]
|
||||
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