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:
12
CHANGELOG.md
12
CHANGELOG.md
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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)
|
||||||
|
@@ -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
1033
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||||
}
|
}
|
||||||
|
@@ -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"]
|
||||||
|
|
||||||
|
@@ -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"]
|
||||||
|
@@ -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{}
|
||||||
|
@@ -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' : ''">
|
||||||
|
@@ -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' : ''">
|
||||||
|
@@ -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)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@@ -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 || {}
|
||||||
|
@@ -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' : ''">
|
||||||
|
Reference in New Issue
Block a user