Skip to content

Commit 72e92d2

Browse files
committed
Merge branch 'release/v1.26.0'
2 parents 56739ce + 803adf2 commit 72e92d2

File tree

11 files changed

+1113
-617
lines changed

11 files changed

+1113
-617
lines changed

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,22 @@
22

33
Notable changes to Mailpit will be documented in this file.
44

5+
## [v1.26.0]
6+
7+
### Feature
8+
- Send API allow separate auth ([#504](https://github.com/axllent/mailpit/issues/504))
9+
- Add Prometheus exporter ([#505](https://github.com/axllent/mailpit/issues/505))
10+
11+
### Chore
12+
- Add MP_DATA_FILE deprecation warning
13+
- Update Go dependencies
14+
- Update node dependencies
15+
16+
### Fix
17+
- Ignore basic auth for OPTIONS requests to API when CORS is set
18+
- Fix sendmail symlink detection for macOS ([#514](https://github.com/axllent/mailpit/issues/514))
19+
20+
521
## [v1.25.1]
622

723
### Chore

cmd/root.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/axllent/mailpit/config"
1010
"github.com/axllent/mailpit/internal/auth"
1111
"github.com/axllent/mailpit/internal/logger"
12+
"github.com/axllent/mailpit/internal/prometheus"
1213
"github.com/axllent/mailpit/internal/smtpd"
1314
"github.com/axllent/mailpit/internal/smtpd/chaos"
1415
"github.com/axllent/mailpit/internal/storage"
@@ -39,6 +40,14 @@ Documentation:
3940
os.Exit(1)
4041
}
4142

43+
// Start Prometheus metrics if enabled
44+
switch prometheus.GetMode() {
45+
case "integrated":
46+
prometheus.StartUpdater()
47+
case "separate":
48+
go prometheus.StartSeparateServer()
49+
}
50+
4251
go server.Listen()
4352

4453
if err := smtpd.Listen(); err != nil {
@@ -108,6 +117,10 @@ func init() {
108117
rootCmd.Flags().BoolVar(&config.DisableHTTPCompression, "disable-http-compression", config.DisableHTTPCompression, "Disable HTTP compression support (web UI & API)")
109118
rootCmd.Flags().BoolVar(&config.HideDeleteAllButton, "hide-delete-all-button", config.HideDeleteAllButton, "Hide the \"Delete all\" button in the web UI")
110119

120+
// Send API
121+
rootCmd.Flags().StringVar(&config.SendAPIAuthFile, "send-api-auth-file", config.SendAPIAuthFile, "A password file for Send API authentication")
122+
rootCmd.Flags().BoolVar(&config.SendAPIAuthAcceptAny, "send-api-auth-accept-any", config.SendAPIAuthAcceptAny, "Accept any username and password for the Send API endpoint, including none")
123+
111124
// SMTP server
112125
rootCmd.Flags().StringVarP(&config.SMTPListen, "smtp", "s", config.SMTPListen, "SMTP bind interface and port")
113126
rootCmd.Flags().StringVar(&config.SMTPAuthFile, "smtp-auth-file", config.SMTPAuthFile, "A password file for SMTP authentication")
@@ -146,6 +159,9 @@ func init() {
146159
rootCmd.Flags().BoolVar(&tools.TagsTitleCase, "tags-title-case", tools.TagsTitleCase, "TitleCase new tags generated from plus-addresses and X-Tags")
147160
rootCmd.Flags().StringVar(&config.TagsDisable, "tags-disable", config.TagsDisable, "Disable auto-tagging, comma separated (eg: plus-addresses,x-tags)")
148161

162+
// Prometheus metrics
163+
rootCmd.Flags().StringVar(&config.PrometheusListen, "enable-prometheus", config.PrometheusListen, "Enable Prometheus metrics: true|false|<ip:port> (eg:'0.0.0.0:9090')")
164+
149165
// Webhook
150166
rootCmd.Flags().StringVar(&config.WebhookURL, "webhook-url", config.WebhookURL, "Send a webhook request for new messages")
151167
rootCmd.Flags().IntVar(&webhook.RateLimit, "webhook-limit", webhook.RateLimit, "Limit webhook requests per second")
@@ -249,6 +265,15 @@ func initConfigFromEnv() {
249265
config.HideDeleteAllButton = true
250266
}
251267

268+
// Send API
269+
config.SendAPIAuthFile = os.Getenv("MP_SEND_API_AUTH_FILE")
270+
if err := auth.SetSendAPIAuth(os.Getenv("MP_SEND_API_AUTH")); err != nil {
271+
logger.Log().Error(err.Error())
272+
}
273+
if getEnabledFromEnv("MP_SEND_API_AUTH_ACCEPT_ANY") {
274+
config.SendAPIAuthAcceptAny = true
275+
}
276+
252277
// SMTP server
253278
if len(os.Getenv("MP_SMTP_BIND_ADDR")) > 0 {
254279
config.SMTPListen = os.Getenv("MP_SMTP_BIND_ADDR")
@@ -346,6 +371,11 @@ func initConfigFromEnv() {
346371
tools.TagsTitleCase = getEnabledFromEnv("MP_TAGS_TITLE_CASE")
347372
config.TagsDisable = os.Getenv("MP_TAGS_DISABLE")
348373

374+
// Prometheus metrics
375+
if len(os.Getenv("MP_ENABLE_PROMETHEUS")) > 0 {
376+
config.PrometheusListen = os.Getenv("MP_ENABLE_PROMETHEUS")
377+
}
378+
349379
// Webhook
350380
if len(os.Getenv("MP_WEBHOOK_URL")) > 0 {
351381
config.WebhookURL = os.Getenv("MP_WEBHOOK_URL")
@@ -362,9 +392,9 @@ func initConfigFromEnv() {
362392
func initDeprecatedConfigFromEnv() {
363393
// deprecated 2024/04/12 - but will not be removed to maintain backwards compatibility
364394
if len(os.Getenv("MP_DATA_FILE")) > 0 {
395+
logger.Log().Warn("ENV MP_DATA_FILE has been deprecated, use MP_DATABASE")
365396
config.Database = os.Getenv("MP_DATA_FILE")
366397
}
367-
368398
// deprecated 2023/03/12
369399
if len(os.Getenv("MP_UI_SSL_CERT")) > 0 {
370400
logger.Log().Warn("ENV MP_UI_SSL_CERT has been deprecated, use MP_UI_TLS_CERT")

config/config.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ var (
7272
// DisableHTTPCompression will explicitly disable HTTP compression in the web UI and API
7373
DisableHTTPCompression bool
7474

75+
// SendAPIAuthFile for Send API authentication
76+
SendAPIAuthFile string
77+
78+
// SendAPIAuthAcceptAny accepts any username/password for the send API endpoint, including none
79+
SendAPIAuthAcceptAny bool
80+
7581
// SMTPTLSCert file
7682
SMTPTLSCert string
7783

@@ -185,6 +191,10 @@ var (
185191
// AllowUntrustedTLS allows untrusted HTTPS connections link checking & screenshot generation
186192
AllowUntrustedTLS bool
187193

194+
// PrometheusListen address for Prometheus metrics server
195+
// Empty = disabled, true= use existing web server, address = separate server
196+
PrometheusListen string
197+
188198
// Version is the default application version, updated on release
189199
Version = "dev"
190200

@@ -289,6 +299,7 @@ func VerifyConfig() error {
289299
return errors.New("[ui] HTTP bind should be in the format of <ip>:<port>")
290300
}
291301

302+
// Web UI & API
292303
if UIAuthFile != "" {
293304
UIAuthFile = filepath.Clean(UIAuthFile)
294305

@@ -323,6 +334,49 @@ func VerifyConfig() error {
323334
}
324335
}
325336

337+
// Send API
338+
if SendAPIAuthFile != "" {
339+
SendAPIAuthFile = filepath.Clean(SendAPIAuthFile)
340+
341+
if !isFile(SendAPIAuthFile) {
342+
return fmt.Errorf("[send-api] password file not found or readable: %s", SendAPIAuthFile)
343+
}
344+
345+
b, err := os.ReadFile(SendAPIAuthFile)
346+
if err != nil {
347+
return err
348+
}
349+
350+
if err := auth.SetSendAPIAuth(string(b)); err != nil {
351+
return err
352+
}
353+
354+
logger.Log().Info("[send-api] enabling basic authentication")
355+
}
356+
357+
if auth.SendAPICredentials != nil && SendAPIAuthAcceptAny {
358+
return errors.New("[send-api] authentication cannot use both credentials and --send-api-auth-accept-any")
359+
}
360+
361+
if SendAPIAuthAcceptAny && auth.UICredentials != nil {
362+
logger.Log().Info("[send-api] disabling authentication")
363+
}
364+
365+
// Prometheus configuration validation
366+
if PrometheusListen != "" {
367+
mode := strings.ToLower(strings.TrimSpace(PrometheusListen))
368+
if mode != "true" && mode != "false" {
369+
// Validate as address for separate server mode
370+
_, err := net.ResolveTCPAddr("tcp", PrometheusListen)
371+
if err != nil {
372+
return fmt.Errorf("[prometheus] %s", err.Error())
373+
}
374+
} else if mode == "true" {
375+
logger.Log().Info("[prometheus] enabling metrics")
376+
}
377+
}
378+
379+
// SMTP server
326380
if SMTPTLSCert != "" && SMTPTLSKey == "" || SMTPTLSCert == "" && SMTPTLSKey != "" {
327381
return errors.New("[smtp] you must provide both an SMTP TLS certificate and a key")
328382
}

go.mod

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ require (
1111
github.com/PuerkitoBio/goquery v1.10.3
1212
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
1313
github.com/axllent/semver v0.0.1
14-
github.com/goccy/go-yaml v1.17.1
14+
github.com/goccy/go-yaml v1.18.0
1515
github.com/gomarkdown/markdown v0.0.0-20250311123330-531bef5e742b
1616
github.com/gorilla/mux v1.8.1
1717
github.com/gorilla/websocket v1.5.3
@@ -21,22 +21,26 @@ require (
2121
github.com/leporo/sqlf v1.4.0
2222
github.com/lithammer/shortuuid/v4 v4.2.0
2323
github.com/mneis/go-telnet v0.0.0-20221017141824-6f643e477c62
24+
github.com/prometheus/client_golang v1.22.0
2425
github.com/rqlite/gorqlite v0.0.0-20250128004930-114c7828b55a
2526
github.com/sirupsen/logrus v1.9.3
2627
github.com/spf13/cobra v1.9.1
2728
github.com/spf13/pflag v1.0.6
2829
github.com/tg123/go-htpasswd v1.2.4
2930
github.com/vanng822/go-premailer v1.24.0
30-
golang.org/x/net v0.40.0
31-
golang.org/x/text v0.25.0
32-
golang.org/x/time v0.11.0
31+
golang.org/x/crypto v0.39.0
32+
golang.org/x/net v0.41.0
33+
golang.org/x/text v0.26.0
34+
golang.org/x/time v0.12.0
3335
modernc.org/sqlite v1.37.1
3436
)
3537

3638
require (
3739
github.com/GehirnInc/crypt v0.0.0-20230320061759-8cc1b52080c5 // indirect
3840
github.com/andybalholm/cascadia v1.3.3 // indirect
41+
github.com/beorn7/perks v1.0.1 // indirect
3942
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
43+
github.com/cespare/xxhash/v2 v2.3.0 // indirect
4044
github.com/dustin/go-humanize v1.0.1 // indirect
4145
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f // indirect
4246
github.com/google/uuid v1.6.0 // indirect
@@ -45,20 +49,24 @@ require (
4549
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 // indirect
4650
github.com/mattn/go-isatty v0.0.20 // indirect
4751
github.com/mattn/go-runewidth v0.0.16 // indirect
52+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
4853
github.com/ncruces/go-strftime v0.1.9 // indirect
49-
github.com/olekukonko/tablewriter v1.0.6 // indirect
54+
github.com/olekukonko/tablewriter v1.0.7 // indirect
5055
github.com/pkg/errors v0.9.1 // indirect
56+
github.com/prometheus/client_model v0.6.2 // indirect
57+
github.com/prometheus/common v0.64.0 // indirect
58+
github.com/prometheus/procfs v0.16.1 // indirect
5159
github.com/reiver/go-oi v1.0.0 // indirect
5260
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
5361
github.com/rivo/uniseg v0.4.7 // indirect
5462
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
5563
github.com/valyala/bytebufferpool v1.0.0 // indirect
5664
github.com/vanng822/css v1.0.1 // indirect
57-
golang.org/x/crypto v0.38.0 // indirect
58-
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect
59-
golang.org/x/image v0.27.0 // indirect
65+
golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 // indirect
66+
golang.org/x/image v0.28.0 // indirect
6067
golang.org/x/sys v0.33.0 // indirect
61-
modernc.org/libc v1.65.8 // indirect
68+
google.golang.org/protobuf v1.36.6 // indirect
69+
modernc.org/libc v1.65.10 // indirect
6270
modernc.org/mathutil v1.7.1 // indirect
6371
modernc.org/memory v1.11.0 // indirect
6472
)

0 commit comments

Comments
 (0)