1
0
mirror of https://github.com/axllent/mailpit.git synced 2025-08-15 20:13:16 +02:00

Merge branch 'release/v1.20.5'

This commit is contained in:
Ralph Slooten
2024-09-26 17:20:25 +02:00
15 changed files with 528 additions and 619 deletions

View File

@@ -2,6 +2,18 @@
Notable changes to Mailpit will be documented in this file. Notable changes to Mailpit will be documented in this file.
## [v1.20.5]
### Chore
- Update node modules
- Use consistent margins for Mailpit label if set
- Improve tag detection in UI
- Improve link detection in the HTML preview
### Fix
- Use correct parameter order in SpamAssassin socket detection ([#364](https://github.com/axllent/mailpit/issues/364))
## [v1.20.4] ## [v1.20.4]
### Chore ### Chore

View File

@@ -305,6 +305,9 @@ func initConfigFromEnv() {
if len(os.Getenv("MP_WEBHOOK_LIMIT")) > 0 { if len(os.Getenv("MP_WEBHOOK_LIMIT")) > 0 {
webhook.RateLimit, _ = strconv.Atoi(os.Getenv("MP_WEBHOOK_LIMIT")) webhook.RateLimit, _ = strconv.Atoi(os.Getenv("MP_WEBHOOK_LIMIT"))
} }
// Demo mode
config.DemoMode = getEnabledFromEnv("MP_DEMO_MODE")
} }
// load deprecated settings from environment and warn // load deprecated settings from environment and warn

View File

@@ -178,6 +178,9 @@ var (
// DisableHTMLCheck DEPRECATED 2024/04/13 - kept here to display console warning only // DisableHTMLCheck DEPRECATED 2024/04/13 - kept here to display console warning only
DisableHTMLCheck = false DisableHTMLCheck = false
// DemoMode disables SMTP relay, link checking & HTTP send functionality
DemoMode = false
) )
// AutoTag struct for auto-tagging // AutoTag struct for auto-tagging
@@ -467,6 +470,12 @@ func VerifyConfig() error {
logger.Log().Warnf("[relay] auto-relaying all new messages via %s:%d", SMTPRelayConfig.Host, SMTPRelayConfig.Port) logger.Log().Warnf("[relay] auto-relaying all new messages via %s:%d", SMTPRelayConfig.Host, SMTPRelayConfig.Port)
} }
if DemoMode {
MaxMessages = 1000
// this deserves a warning
logger.Log().Info("demo mode enabled")
}
return nil return nil
} }

View File

@@ -71,7 +71,7 @@ func Ping() error {
} }
var client *spamc.Client var client *spamc.Client
if strings.HasPrefix("unix:", service) { if strings.HasPrefix(service, "unix:") {
client = spamc.NewUnix(strings.TrimLeft(service, "unix:")) client = spamc.NewUnix(strings.TrimLeft(service, "unix:"))
} else { } else {
client = spamc.NewTCP(service, timeout) client = spamc.NewTCP(service, timeout)
@@ -112,7 +112,7 @@ func Check(msg []byte) (Result, error) {
} }
} else { } else {
var client *spamc.Client var client *spamc.Client
if strings.HasPrefix("unix:", service) { if strings.HasPrefix(service, "unix:") {
client = spamc.NewUnix(strings.TrimLeft(service, "unix:")) client = spamc.NewUnix(strings.TrimLeft(service, "unix:"))
} else { } else {
client = spamc.NewTCP(service, timeout) client = spamc.NewTCP(service, timeout)

View File

@@ -61,25 +61,32 @@ func pruneMessages() {
// prune using `--max` if set // prune using `--max` if set
if config.MaxMessages > 0 { if config.MaxMessages > 0 {
q := sqlf.Select("ID, Size"). total := CountTotal()
From(tenant("mailbox")). if total > float64(config.MaxAgeInHours) {
OrderBy("Created DESC"). offset := config.MaxMessages
Limit(5000). if config.DemoMode {
Offset(config.MaxMessages) offset = 500
}
q := sqlf.Select("ID, Size").
From(tenant("mailbox")).
OrderBy("Created DESC").
Limit(5000).
Offset(offset)
if err := q.QueryAndClose(context.TODO(), db, func(row *sql.Rows) { if err := q.QueryAndClose(context.TODO(), db, func(row *sql.Rows) {
var id string var id string
if err := row.Scan(&id, &size); err != nil { if err := row.Scan(&id, &size); err != nil {
logger.Log().Errorf("[db] %s", err.Error())
return
}
ids = append(ids, id)
prunedSize = prunedSize + int64(size)
}); err != nil {
logger.Log().Errorf("[db] %s", err.Error()) logger.Log().Errorf("[db] %s", err.Error())
return return
} }
ids = append(ids, id)
prunedSize = prunedSize + int64(size)
}); err != nil {
logger.Log().Errorf("[db] %s", err.Error())
return
} }
} }
@@ -166,6 +173,10 @@ func pruneMessages() {
logMessagesDeleted(len(ids)) logMessagesDeleted(len(ids))
if config.DemoMode {
vacuumDb()
}
websockets.Broadcast("prune", nil) websockets.Broadcast("prune", nil)
} }

1033
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -31,7 +31,7 @@
"@types/bootstrap": "^5.2.7", "@types/bootstrap": "^5.2.7",
"@types/tinycon": "^0.6.3", "@types/tinycon": "^0.6.3",
"@vue/compiler-sfc": "^3.2.37", "@vue/compiler-sfc": "^3.2.37",
"esbuild": "^0.23.0", "esbuild": "^0.24.0",
"esbuild-plugin-vue-next": "^0.1.4", "esbuild-plugin-vue-next": "^0.1.4",
"esbuild-sass-plugin": "^3.0.0" "esbuild-sass-plugin": "^3.0.0"
} }

View File

@@ -601,6 +601,11 @@ func LinkCheck(w http.ResponseWriter, r *http.Request) {
// 200: LinkCheckResponse // 200: LinkCheckResponse
// default: ErrorResponse // default: ErrorResponse
if config.DemoMode {
httpError(w, "this functionality has been disabled for demonstration purposes")
return
}
vars := mux.Vars(r) vars := mux.Vars(r)
id := vars["id"] id := vars["id"]

View File

@@ -37,6 +37,11 @@ func ReleaseMessage(w http.ResponseWriter, r *http.Request) {
// 200: OKResponse // 200: OKResponse
// default: ErrorResponse // default: ErrorResponse
if config.DemoMode {
httpError(w, "this functionality has been disabled for demonstration purposes")
return
}
vars := mux.Vars(r) vars := mux.Vars(r)
id := vars["id"] id := vars["id"]

View File

@@ -11,6 +11,7 @@ import (
"net/mail" "net/mail"
"strings" "strings"
"github.com/axllent/mailpit/config"
"github.com/axllent/mailpit/internal/tools" "github.com/axllent/mailpit/internal/tools"
"github.com/axllent/mailpit/server/smtpd" "github.com/axllent/mailpit/server/smtpd"
"github.com/jhillyerd/enmime" "github.com/jhillyerd/enmime"
@@ -141,6 +142,11 @@ func SendMessageHandler(w http.ResponseWriter, r *http.Request) {
// 200: sendMessageResponse // 200: sendMessageResponse
// default: jsonErrorResponse // default: jsonErrorResponse
if config.DemoMode {
httpJSONError(w, "this functionality has been disabled for demonstration purposes")
return
}
decoder := json.NewDecoder(r.Body) decoder := json.NewDecoder(r.Body)
data := SendRequest{} data := SendRequest{}

View File

@@ -65,9 +65,10 @@ export default {
<template> <template>
<template v-if="!modals"> <template v-if="!modals">
<div class="text-center badge text-bg-primary py-2 mt-2 w-100 text-truncate fw-normal" <div class="text-center badge text-bg-primary py-2 my-2 w-100" v-if="mailbox.uiConfig.Label">
v-if="mailbox.uiConfig.Label"> <div class="text-truncate fw-normal">
{{ mailbox.uiConfig.Label }} {{ mailbox.uiConfig.Label }}
</div>
</div> </div>
<div class="list-group my-2" :class="mailbox.uiConfig.Label ? 'mt-0' : ''"> <div class="list-group my-2" :class="mailbox.uiConfig.Label ? 'mt-0' : ''">

View File

@@ -52,9 +52,10 @@ export default {
<template> <template>
<template v-if="!modals"> <template v-if="!modals">
<div class="text-center badge text-bg-primary py-2 mt-2 w-100 text-truncate fw-normal" <div class="text-center badge text-bg-primary py-2 my-2 w-100" v-if="mailbox.uiConfig.Label">
v-if="mailbox.uiConfig.Label"> <div class="text-truncate fw-normal">
{{ mailbox.uiConfig.Label }} {{ mailbox.uiConfig.Label }}
</div>
</div> </div>
<div class="list-group my-2" :class="mailbox.uiConfig.Label ? 'mt-0' : ''"> <div class="list-group my-2" :class="mailbox.uiConfig.Label ? 'mt-0' : ''">

View File

@@ -22,7 +22,7 @@ export default {
return false return false
} }
let re = new RegExp(`\\btag:("${tag}"|${tag}\\b)`, 'i') let re = new RegExp(`(^|\\s)tag:("${tag}"|${tag}\\b)`, 'i')
return query.match(re) return query.match(re)
}, },

View File

@@ -182,7 +182,7 @@ export default {
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]'); const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
[...tooltipTriggerList].map(tooltipTriggerEl => new Tooltip(tooltipTriggerEl)) [...tooltipTriggerList].map(tooltipTriggerEl => new Tooltip(tooltipTriggerEl))
// delay 0.2s until vue has rendered the iframe content // delay 0.5s until vue has rendered the iframe content
window.setTimeout(() => { window.setTimeout(() => {
let p = document.getElementById('preview-html') let p = document.getElementById('preview-html')
if (p && typeof p.contentWindow.document.body == 'object') { if (p && typeof p.contentWindow.document.body == 'object') {
@@ -193,14 +193,14 @@ export default {
let anchorEl = anchorEls[i] let anchorEl = anchorEls[i]
let href = anchorEl.getAttribute('href') let href = anchorEl.getAttribute('href')
if (href && href.match(/^http/)) { if (href && href.match(/^https?:\/\//i)) {
anchorEl.setAttribute('target', '_blank') anchorEl.setAttribute('target', '_blank')
} }
} }
} catch (error) { } } catch (error) { }
this.resizeIFrames() this.resizeIFrames()
} }
}, 200) }, 500)
// html highlighting // html highlighting
window.Prism = window.Prism || {} window.Prism = window.Prism || {}

View File

@@ -544,9 +544,10 @@ export default {
<div class="row flex-fill" style="min-height:0"> <div class="row flex-fill" style="min-height:0">
<div class="d-none d-xl-flex col-xl-3 h-100 flex-column"> <div class="d-none d-xl-flex col-xl-3 h-100 flex-column">
<div class="text-center badge text-bg-primary py-2 mt-2 w-100 text-truncate fw-normal" <div class="text-center badge text-bg-primary py-2 my-2 w-100" v-if="mailbox.uiConfig.Label">
v-if="mailbox.uiConfig.Label"> <div class="text-truncate fw-normal">
{{ mailbox.uiConfig.Label }} {{ mailbox.uiConfig.Label }}
</div>
</div> </div>
<div class="list-group my-2" :class="mailbox.uiConfig.Label ? 'mt-0' : ''"> <div class="list-group my-2" :class="mailbox.uiConfig.Label ? 'mt-0' : ''">