mirror of
https://github.com/axllent/mailpit.git
synced 2024-12-26 22:56:43 +02:00
Feature: Add optional relay recipient blocklist (#333)
This commit is contained in:
parent
406fe56fc6
commit
6947c2a621
@ -275,6 +275,7 @@ func initConfigFromEnv() {
|
|||||||
config.SMTPRelayConfig.Secret = os.Getenv("MP_SMTP_RELAY_SECRET")
|
config.SMTPRelayConfig.Secret = os.Getenv("MP_SMTP_RELAY_SECRET")
|
||||||
config.SMTPRelayConfig.ReturnPath = os.Getenv("MP_SMTP_RELAY_RETURN_PATH")
|
config.SMTPRelayConfig.ReturnPath = os.Getenv("MP_SMTP_RELAY_RETURN_PATH")
|
||||||
config.SMTPRelayConfig.AllowedRecipients = os.Getenv("MP_SMTP_RELAY_ALLOWED_RECIPIENTS")
|
config.SMTPRelayConfig.AllowedRecipients = os.Getenv("MP_SMTP_RELAY_ALLOWED_RECIPIENTS")
|
||||||
|
config.SMTPRelayConfig.BlockedRecipients = os.Getenv("MP_SMTP_RELAY_BLOCKED_RECIPIENTS")
|
||||||
|
|
||||||
// POP3 server
|
// POP3 server
|
||||||
if len(os.Getenv("MP_POP3_BIND_ADDR")) > 0 {
|
if len(os.Getenv("MP_POP3_BIND_ADDR")) > 0 {
|
||||||
|
@ -191,6 +191,9 @@ type SMTPRelayConfigStruct struct {
|
|||||||
ReturnPath string `yaml:"return-path"` // allow overriding the bounce address
|
ReturnPath string `yaml:"return-path"` // allow overriding the bounce address
|
||||||
AllowedRecipients string `yaml:"allowed-recipients"` // regex, if set needs to match for mails to be relayed
|
AllowedRecipients string `yaml:"allowed-recipients"` // regex, if set needs to match for mails to be relayed
|
||||||
AllowedRecipientsRegexp *regexp.Regexp // compiled regexp using AllowedRecipients
|
AllowedRecipientsRegexp *regexp.Regexp // compiled regexp using AllowedRecipients
|
||||||
|
BlockedRecipients string `yaml:"blocked-recipients"` // regex, if set prevents relating to these addresses
|
||||||
|
BlockedRecipientsRegexp *regexp.Regexp // compiled regexp using BlockedRecipients
|
||||||
|
|
||||||
// DEPRECATED 2024/03/12
|
// DEPRECATED 2024/03/12
|
||||||
RecipientAllowlist string `yaml:"recipient-allowlist"`
|
RecipientAllowlist string `yaml:"recipient-allowlist"`
|
||||||
}
|
}
|
||||||
@ -433,12 +436,12 @@ func VerifyConfig() error {
|
|||||||
if SMTPRelayAll {
|
if SMTPRelayAll {
|
||||||
logger.Log().Warnf("[relay] ignoring smtp-relay-matching when smtp-relay-all is enabled")
|
logger.Log().Warnf("[relay] ignoring smtp-relay-matching when smtp-relay-all is enabled")
|
||||||
} else {
|
} else {
|
||||||
restrictRegexp, err := regexp.Compile(SMTPRelayMatching)
|
re, err := regexp.Compile(SMTPRelayMatching)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("[relay] failed to compile smtp-relay-matching regexp: %s", err.Error())
|
return fmt.Errorf("[relay] failed to compile smtp-relay-matching regexp: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
SMTPRelayMatchingRegexp = restrictRegexp
|
SMTPRelayMatchingRegexp = re
|
||||||
logger.Log().Infof("[relay] auto-relaying new messages to recipients matching \"%s\" via %s:%d",
|
logger.Log().Infof("[relay] auto-relaying new messages to recipients matching \"%s\" via %s:%d",
|
||||||
SMTPRelayMatching, SMTPRelayConfig.Host, SMTPRelayConfig.Port)
|
SMTPRelayMatching, SMTPRelayConfig.Host, SMTPRelayConfig.Port)
|
||||||
}
|
}
|
||||||
@ -525,14 +528,23 @@ func validateRelayConfig() error {
|
|||||||
logger.Log().Infof("[smtp] enabling message relaying via %s:%d", SMTPRelayConfig.Host, SMTPRelayConfig.Port)
|
logger.Log().Infof("[smtp] enabling message relaying via %s:%d", SMTPRelayConfig.Host, SMTPRelayConfig.Port)
|
||||||
|
|
||||||
if SMTPRelayConfig.AllowedRecipients != "" {
|
if SMTPRelayConfig.AllowedRecipients != "" {
|
||||||
allowlistRegexp, err := regexp.Compile(SMTPRelayConfig.AllowedRecipients)
|
re, err := regexp.Compile(SMTPRelayConfig.AllowedRecipients)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("[smtp] failed to compile relay recipient allowlist regexp: %s", err.Error())
|
return fmt.Errorf("[smtp] failed to compile relay recipient allowlist regexp: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
SMTPRelayConfig.AllowedRecipientsRegexp = allowlistRegexp
|
SMTPRelayConfig.AllowedRecipientsRegexp = re
|
||||||
logger.Log().Infof("[smtp] relay recipient allowlist is active with the following regexp: %s", SMTPRelayConfig.AllowedRecipients)
|
logger.Log().Infof("[smtp] relay recipient allowlist is active with the following regexp: %s", SMTPRelayConfig.AllowedRecipients)
|
||||||
|
}
|
||||||
|
|
||||||
|
if SMTPRelayConfig.BlockedRecipients != "" {
|
||||||
|
re, err := regexp.Compile(SMTPRelayConfig.BlockedRecipients)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("[smtp] failed to compile relay recipient blocklist regexp: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
SMTPRelayConfig.BlockedRecipientsRegexp = re
|
||||||
|
logger.Log().Infof("[smtp] relay recipient blocklist is active with the following regexp: %s", SMTPRelayConfig.BlockedRecipients)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -9,18 +9,13 @@ import (
|
|||||||
"net/mail"
|
"net/mail"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/axllent/mailpit/config"
|
"github.com/axllent/mailpit/config"
|
||||||
"github.com/axllent/mailpit/internal/htmlcheck"
|
"github.com/axllent/mailpit/internal/htmlcheck"
|
||||||
"github.com/axllent/mailpit/internal/linkcheck"
|
"github.com/axllent/mailpit/internal/linkcheck"
|
||||||
"github.com/axllent/mailpit/internal/logger"
|
|
||||||
"github.com/axllent/mailpit/internal/spamassassin"
|
"github.com/axllent/mailpit/internal/spamassassin"
|
||||||
"github.com/axllent/mailpit/internal/storage"
|
"github.com/axllent/mailpit/internal/storage"
|
||||||
"github.com/axllent/mailpit/internal/tools"
|
|
||||||
"github.com/axllent/mailpit/server/smtpd"
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/lithammer/shortuuid/v4"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetMessages returns a paginated list of messages as JSON
|
// GetMessages returns a paginated list of messages as JSON
|
||||||
@ -523,135 +518,6 @@ func SetReadStatus(w http.ResponseWriter, r *http.Request) {
|
|||||||
_, _ = w.Write([]byte("ok"))
|
_, _ = w.Write([]byte("ok"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReleaseMessage (method: POST) will release a message via a pre-configured external SMTP server.
|
|
||||||
func ReleaseMessage(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// swagger:route POST /api/v1/message/{ID}/release message ReleaseMessage
|
|
||||||
//
|
|
||||||
// # Release message
|
|
||||||
//
|
|
||||||
// Release a message via a pre-configured external SMTP server. This is only enabled if message relaying has been configured.
|
|
||||||
//
|
|
||||||
// Consumes:
|
|
||||||
// - application/json
|
|
||||||
//
|
|
||||||
// Produces:
|
|
||||||
// - text/plain
|
|
||||||
//
|
|
||||||
// Schemes: http, https
|
|
||||||
//
|
|
||||||
// Responses:
|
|
||||||
// 200: OKResponse
|
|
||||||
// default: ErrorResponse
|
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
|
||||||
|
|
||||||
id := vars["id"]
|
|
||||||
|
|
||||||
msg, err := storage.GetMessageRaw(id)
|
|
||||||
if err != nil {
|
|
||||||
fourOFour(w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder := json.NewDecoder(r.Body)
|
|
||||||
|
|
||||||
data := releaseMessageRequestBody{}
|
|
||||||
|
|
||||||
if err := decoder.Decode(&data); err != nil {
|
|
||||||
httpError(w, err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, to := range data.To {
|
|
||||||
address, err := mail.ParseAddress(to)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
httpError(w, "Invalid email address: "+to)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.SMTPRelayConfig.AllowedRecipientsRegexp != nil && !config.SMTPRelayConfig.AllowedRecipientsRegexp.MatchString(address.Address) {
|
|
||||||
httpError(w, "Mail address does not match allowlist: "+to)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(data.To) == 0 {
|
|
||||||
httpError(w, "No valid addresses found")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
reader := bytes.NewReader(msg)
|
|
||||||
m, err := mail.ReadMessage(reader)
|
|
||||||
if err != nil {
|
|
||||||
httpError(w, err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fromAddresses, err := m.Header.AddressList("From")
|
|
||||||
if err != nil {
|
|
||||||
httpError(w, err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(fromAddresses) == 0 {
|
|
||||||
httpError(w, "No From header found")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
from := fromAddresses[0].Address
|
|
||||||
|
|
||||||
// if sender is used, then change from to the sender
|
|
||||||
if senders, err := m.Header.AddressList("Sender"); err == nil {
|
|
||||||
from = senders[0].Address
|
|
||||||
}
|
|
||||||
|
|
||||||
msg, err = tools.RemoveMessageHeaders(msg, []string{"Bcc"})
|
|
||||||
if err != nil {
|
|
||||||
httpError(w, err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the Return-Path and SMTP mfrom
|
|
||||||
if config.SMTPRelayConfig.ReturnPath != "" {
|
|
||||||
if m.Header.Get("Return-Path") != "<"+config.SMTPRelayConfig.ReturnPath+">" {
|
|
||||||
msg, err = tools.RemoveMessageHeaders(msg, []string{"Return-Path"})
|
|
||||||
if err != nil {
|
|
||||||
httpError(w, err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
msg = append([]byte("Return-Path: <"+config.SMTPRelayConfig.ReturnPath+">\r\n"), msg...)
|
|
||||||
}
|
|
||||||
|
|
||||||
from = config.SMTPRelayConfig.ReturnPath
|
|
||||||
}
|
|
||||||
|
|
||||||
// update message date
|
|
||||||
msg, err = tools.UpdateMessageHeader(msg, "Date", time.Now().Format(time.RFC1123Z))
|
|
||||||
if err != nil {
|
|
||||||
httpError(w, err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// generate unique ID
|
|
||||||
uid := shortuuid.New() + "@mailpit"
|
|
||||||
// update Message-Id with unique ID
|
|
||||||
msg, err = tools.UpdateMessageHeader(msg, "Message-Id", "<"+uid+">")
|
|
||||||
if err != nil {
|
|
||||||
httpError(w, err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := smtpd.Send(from, data.To, msg); err != nil {
|
|
||||||
logger.Log().Errorf("[smtp] error sending message: %s", err.Error())
|
|
||||||
httpError(w, "SMTP error: "+err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Add("Content-Type", "text/plain")
|
|
||||||
_, _ = w.Write([]byte("ok"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTMLCheck returns a summary of the HTML client support
|
// HTMLCheck returns a summary of the HTML client support
|
||||||
func HTMLCheck(w http.ResponseWriter, r *http.Request) {
|
func HTMLCheck(w http.ResponseWriter, r *http.Request) {
|
||||||
// swagger:route GET /api/v1/message/{ID}/html-check Other HTMLCheck
|
// swagger:route GET /api/v1/message/{ID}/html-check Other HTMLCheck
|
||||||
|
167
server/apiv1/release.go
Normal file
167
server/apiv1/release.go
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
package apiv1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/mail"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/axllent/mailpit/config"
|
||||||
|
"github.com/axllent/mailpit/internal/logger"
|
||||||
|
"github.com/axllent/mailpit/internal/storage"
|
||||||
|
"github.com/axllent/mailpit/internal/tools"
|
||||||
|
"github.com/axllent/mailpit/server/smtpd"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/lithammer/shortuuid/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReleaseMessage (method: POST) will release a message via a pre-configured external SMTP server.
|
||||||
|
func ReleaseMessage(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// swagger:route POST /api/v1/message/{ID}/release message ReleaseMessage
|
||||||
|
//
|
||||||
|
// # Release message
|
||||||
|
//
|
||||||
|
// Release a message via a pre-configured external SMTP server. This is only enabled if message relaying has been configured.
|
||||||
|
//
|
||||||
|
// Consumes:
|
||||||
|
// - application/json
|
||||||
|
//
|
||||||
|
// Produces:
|
||||||
|
// - text/plain
|
||||||
|
//
|
||||||
|
// Schemes: http, https
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: OKResponse
|
||||||
|
// default: ErrorResponse
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
|
||||||
|
id := vars["id"]
|
||||||
|
|
||||||
|
msg, err := storage.GetMessageRaw(id)
|
||||||
|
if err != nil {
|
||||||
|
fourOFour(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder := json.NewDecoder(r.Body)
|
||||||
|
|
||||||
|
data := releaseMessageRequestBody{}
|
||||||
|
|
||||||
|
if err := decoder.Decode(&data); err != nil {
|
||||||
|
httpError(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
blocked := []string{}
|
||||||
|
notAllowed := []string{}
|
||||||
|
|
||||||
|
for _, to := range data.To {
|
||||||
|
address, err := mail.ParseAddress(to)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
httpError(w, "Invalid email address: "+to)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.SMTPRelayConfig.AllowedRecipientsRegexp != nil && !config.SMTPRelayConfig.AllowedRecipientsRegexp.MatchString(address.Address) {
|
||||||
|
notAllowed = append(notAllowed, to)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.SMTPRelayConfig.BlockedRecipientsRegexp != nil && config.SMTPRelayConfig.BlockedRecipientsRegexp.MatchString(address.Address) {
|
||||||
|
blocked = append(blocked, to)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(notAllowed) > 0 {
|
||||||
|
addr := tools.Plural(len(notAllowed), "Address", "Addresses")
|
||||||
|
httpError(w, "Failed: "+addr+" do not match the allowlist: "+strings.Join(notAllowed, ", "))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(blocked) > 0 {
|
||||||
|
addr := tools.Plural(len(blocked), "Address", "Addresses")
|
||||||
|
httpError(w, "Failed: "+addr+" found on blocklist: "+strings.Join(blocked, ", "))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(data.To) == 0 {
|
||||||
|
httpError(w, "No valid addresses found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
reader := bytes.NewReader(msg)
|
||||||
|
m, err := mail.ReadMessage(reader)
|
||||||
|
if err != nil {
|
||||||
|
httpError(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fromAddresses, err := m.Header.AddressList("From")
|
||||||
|
if err != nil {
|
||||||
|
httpError(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(fromAddresses) == 0 {
|
||||||
|
httpError(w, "No From header found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
from := fromAddresses[0].Address
|
||||||
|
|
||||||
|
// if sender is used, then change from to the sender
|
||||||
|
if senders, err := m.Header.AddressList("Sender"); err == nil {
|
||||||
|
from = senders[0].Address
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err = tools.RemoveMessageHeaders(msg, []string{"Bcc"})
|
||||||
|
if err != nil {
|
||||||
|
httpError(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the Return-Path and SMTP from
|
||||||
|
if config.SMTPRelayConfig.ReturnPath != "" {
|
||||||
|
if m.Header.Get("Return-Path") != "<"+config.SMTPRelayConfig.ReturnPath+">" {
|
||||||
|
msg, err = tools.RemoveMessageHeaders(msg, []string{"Return-Path"})
|
||||||
|
if err != nil {
|
||||||
|
httpError(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
msg = append([]byte("Return-Path: <"+config.SMTPRelayConfig.ReturnPath+">\r\n"), msg...)
|
||||||
|
}
|
||||||
|
|
||||||
|
from = config.SMTPRelayConfig.ReturnPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// update message date
|
||||||
|
msg, err = tools.UpdateMessageHeader(msg, "Date", time.Now().Format(time.RFC1123Z))
|
||||||
|
if err != nil {
|
||||||
|
httpError(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate unique ID
|
||||||
|
uid := shortuuid.New() + "@mailpit"
|
||||||
|
// update Message-Id with unique ID
|
||||||
|
msg, err = tools.UpdateMessageHeader(msg, "Message-Id", "<"+uid+">")
|
||||||
|
if err != nil {
|
||||||
|
httpError(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := smtpd.Send(from, data.To, msg); err != nil {
|
||||||
|
logger.Log().Errorf("[smtp] error sending message: %s", err.Error())
|
||||||
|
httpError(w, "SMTP error: "+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Add("Content-Type", "text/plain")
|
||||||
|
_, _ = w.Write([]byte("ok"))
|
||||||
|
}
|
@ -24,6 +24,8 @@ type webUIConfiguration struct {
|
|||||||
ReturnPath string
|
ReturnPath string
|
||||||
// Only allow relaying to these recipients (regex)
|
// Only allow relaying to these recipients (regex)
|
||||||
AllowedRecipients string
|
AllowedRecipients string
|
||||||
|
// Block relaying to these recipients (regex)
|
||||||
|
BlockedRecipients string
|
||||||
// DEPRECATED 2024/03/12
|
// DEPRECATED 2024/03/12
|
||||||
// swagger:ignore
|
// swagger:ignore
|
||||||
RecipientAllowlist string
|
RecipientAllowlist string
|
||||||
@ -61,6 +63,7 @@ func WebUIConfig(w http.ResponseWriter, _ *http.Request) {
|
|||||||
conf.MessageRelay.SMTPServer = fmt.Sprintf("%s:%d", config.SMTPRelayConfig.Host, config.SMTPRelayConfig.Port)
|
conf.MessageRelay.SMTPServer = fmt.Sprintf("%s:%d", config.SMTPRelayConfig.Host, config.SMTPRelayConfig.Port)
|
||||||
conf.MessageRelay.ReturnPath = config.SMTPRelayConfig.ReturnPath
|
conf.MessageRelay.ReturnPath = config.SMTPRelayConfig.ReturnPath
|
||||||
conf.MessageRelay.AllowedRecipients = config.SMTPRelayConfig.AllowedRecipients
|
conf.MessageRelay.AllowedRecipients = config.SMTPRelayConfig.AllowedRecipients
|
||||||
|
conf.MessageRelay.BlockedRecipients = config.SMTPRelayConfig.BlockedRecipients
|
||||||
// DEPRECATED 2024/03/12
|
// DEPRECATED 2024/03/12
|
||||||
conf.MessageRelay.RecipientAllowlist = config.SMTPRelayConfig.AllowedRecipients
|
conf.MessageRelay.RecipientAllowlist = config.SMTPRelayConfig.AllowedRecipients
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,19 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func autoRelayMessage(from string, to []string, data *[]byte) {
|
func autoRelayMessage(from string, to []string, data *[]byte) {
|
||||||
|
if config.SMTPRelayConfig.BlockedRecipientsRegexp != nil {
|
||||||
|
filteredTo := []string{}
|
||||||
|
for _, address := range to {
|
||||||
|
if config.SMTPRelayConfig.BlockedRecipientsRegexp.MatchString(address) {
|
||||||
|
logger.Log().Debugf("[smtp] ignoring auto-relay to %s: found in blocklist", address)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
filteredTo = append(filteredTo, address)
|
||||||
|
}
|
||||||
|
to = filteredTo
|
||||||
|
}
|
||||||
|
|
||||||
if len(to) == 0 {
|
if len(to) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ export default {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="modal fade" id="ReleaseModal" tabindex="-1" aria-labelledby="AppInfoModalLabel" aria-hidden="true">
|
<div class="modal fade" id="ReleaseModal" tabindex="-1" aria-labelledby="AppInfoModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-lg" v-if="message">
|
<div class="modal-dialog modal-xl" v-if="message">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h1 class="modal-title fs-5" id="AppInfoModalLabel">Release email</h1>
|
<h1 class="modal-title fs-5" id="AppInfoModalLabel">Release email</h1>
|
||||||
@ -125,11 +125,39 @@ export default {
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-text text-center" v-if="mailbox.uiConfig.MessageRelay.AllowedRecipients != ''">
|
|
||||||
|
<h6>Notes</h6>
|
||||||
|
<ul>
|
||||||
|
<li v-if="mailbox.uiConfig.MessageRelay.AllowedRecipients != ''" class="form-text">
|
||||||
|
A recipient <b>allowlist</b> has been configured. Any mail address not matching the following will be rejected:
|
||||||
|
<code>{{ mailbox.uiConfig.MessageRelay.AllowedRecipients }}</code>
|
||||||
|
</li>
|
||||||
|
<li v-if="mailbox.uiConfig.MessageRelay.BlockedRecipients != ''" class="form-text">
|
||||||
|
A recipient <b>blocklist</b> has been configured. Any mail address matching the following will be rejected:
|
||||||
|
<code>{{ mailbox.uiConfig.MessageRelay.BlockedRecipients }}</code>
|
||||||
|
</li>
|
||||||
|
<li class="form-text">
|
||||||
|
For testing purposes, a new unique <code>Message-Id</code> will be generated on send.
|
||||||
|
</li>
|
||||||
|
<li class="form-text">
|
||||||
|
SMTP delivery failures will bounce back to
|
||||||
|
<code v-if="mailbox.uiConfig.MessageRelay.ReturnPath != ''">
|
||||||
|
{{ mailbox.uiConfig.MessageRelay.ReturnPath }}
|
||||||
|
</code>
|
||||||
|
<code v-else>{{ message.ReturnPath }}</code>.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<!-- <div class="form-text text-center" v-if="mailbox.uiConfig.MessageRelay.AllowedRecipients != ''">
|
||||||
Note: A recipient allowlist has been configured. Any mail address not matching it will be
|
Note: A recipient allowlist has been configured. Any mail address not matching it will be
|
||||||
rejected.<br class="d-none d-md-inline">
|
rejected.<br class="d-none d-md-inline">
|
||||||
Allowed recipients: <b>{{ mailbox.uiConfig.MessageRelay.AllowedRecipients }}</b>
|
Allowed recipients: <b>{{ mailbox.uiConfig.MessageRelay.AllowedRecipients }}</b>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-text text-center" v-if="mailbox.uiConfig.MessageRelay.BlockedRecipients != ''">
|
||||||
|
Note: A recipient blocklist has been configured. Any mail address matching it will be
|
||||||
|
rejected.<br class="d-none d-md-inline">
|
||||||
|
Blocked recipients: <b>{{ mailbox.uiConfig.MessageRelay.BlockedRecipients }}</b>
|
||||||
|
</div>
|
||||||
<div class="form-text text-center">
|
<div class="form-text text-center">
|
||||||
Note: For testing purposes, a unique Message-Id will be generated on send.
|
Note: For testing purposes, a unique Message-Id will be generated on send.
|
||||||
<br class="d-none d-md-inline">
|
<br class="d-none d-md-inline">
|
||||||
@ -138,7 +166,7 @@ export default {
|
|||||||
{{ mailbox.uiConfig.MessageRelay.ReturnPath }}
|
{{ mailbox.uiConfig.MessageRelay.ReturnPath }}
|
||||||
</b>
|
</b>
|
||||||
<b v-else>{{ message.ReturnPath }}</b>.
|
<b v-else>{{ message.ReturnPath }}</b>.
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
|
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||||
|
@ -1720,6 +1720,10 @@
|
|||||||
"description": "Only allow relaying to these recipients (regex)",
|
"description": "Only allow relaying to these recipients (regex)",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"BlockedRecipients": {
|
||||||
|
"description": "Block relaying to these recipients (regex)",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"Enabled": {
|
"Enabled": {
|
||||||
"description": "Whether message relaying (release) is enabled",
|
"description": "Whether message relaying (release) is enabled",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
Loading…
Reference in New Issue
Block a user