Skip to content

Commit c7d7810

Browse files
committed
Merge branch 'release/v1.22.3'
2 parents f40f955 + d26e317 commit c7d7810

File tree

16 files changed

+748
-330
lines changed

16 files changed

+748
-330
lines changed

CHANGELOG.md

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

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

5+
## [v1.22.3]
6+
7+
### Feature
8+
- Add dump feature to export all raw messages to a local directory ([#443](https://github.com/axllent/mailpit/issues/443))
9+
10+
### Chore
11+
- Update node dependencies
12+
- Update Go dependencies
13+
- Specify Docker health check start period and interval ([#439](https://github.com/axllent/mailpit/issues/439))
14+
15+
### Fix
16+
- Correctly detect maximum SMTP recipient limits, add test
17+
- Update Swagger JSON to prevent overflow ([#442](https://github.com/axllent/mailpit/issues/442))
18+
- Include font/woff content type to embedded controller
19+
- Replace TrimLeft with TrimPrefix for webroot path handling ([#441](https://github.com/axllent/mailpit/issues/441))
20+
21+
522
## [v1.22.2]
623

724
### Chore

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,6 @@ RUN apk upgrade --no-cache && apk add --no-cache tzdata
2525

2626
EXPOSE 1025/tcp 1110/tcp 8025/tcp
2727

28-
HEALTHCHECK --interval=15s CMD /mailpit readyz
28+
HEALTHCHECK --interval=15s --start-period=10s --start-interval=1s CMD /mailpit readyz
2929

3030
ENTRYPOINT ["/mailpit"]

cmd/dump.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package cmd
2+
3+
import (
4+
"github.com/axllent/mailpit/config"
5+
"github.com/axllent/mailpit/internal/dump"
6+
"github.com/axllent/mailpit/internal/logger"
7+
"github.com/spf13/cobra"
8+
)
9+
10+
// dumpCmd represents the dump command
11+
var dumpCmd = &cobra.Command{
12+
Use: "dump <database> <output-dir>",
13+
Short: "Dump all messages from a database to a directory",
14+
Long: `Dump all messages stored in Mailpit into a local directory as individual files.
15+
16+
The database can either be the database file (eg: --database /var/lib/mailpit/mailpit.db) or a
17+
URL of a running Mailpit instance (eg: --http http://127.0.0.1/). If dumping over HTTP, the URL
18+
should be the base URL of your running Mailpit instance, not the link to the API itself.`,
19+
Args: cobra.ExactArgs(1),
20+
Run: func(cmd *cobra.Command, args []string) {
21+
if err := dump.Sync(args[0]); err != nil {
22+
logger.Log().Fatal(err)
23+
}
24+
},
25+
}
26+
27+
func init() {
28+
rootCmd.AddCommand(dumpCmd)
29+
30+
dumpCmd.Flags().SortFlags = false
31+
32+
dumpCmd.Flags().StringVar(&config.Database, "database", config.Database, "Dump messages directly from a database file")
33+
dumpCmd.Flags().StringVar(&config.TenantID, "tenant-id", config.TenantID, "Database tenant ID to isolate data (optional)")
34+
dumpCmd.Flags().StringVar(&dump.URL, "http", dump.URL, "Dump messages via HTTP API (base URL of running Mailpit instance)")
35+
dumpCmd.Flags().BoolVarP(&logger.VerboseLogging, "verbose", "v", logger.VerboseLogging, "Verbose logging")
36+
}

go.mod

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,33 @@
11
module github.com/axllent/mailpit
22

3-
go 1.23
3+
go 1.23.0
44

55
toolchain go1.23.2
66

77
require (
8-
github.com/PuerkitoBio/goquery v1.10.1
8+
github.com/PuerkitoBio/goquery v1.10.2
99
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
1010
github.com/axllent/semver v0.0.1
1111
github.com/gomarkdown/markdown v0.0.0-20250207164621-7a1f277a159e
1212
github.com/gorilla/mux v1.8.1
1313
github.com/gorilla/websocket v1.5.3
1414
github.com/jhillyerd/enmime v1.3.0
1515
github.com/klauspost/compress v1.17.11
16-
github.com/kovidgoyal/imaging v1.6.3
16+
github.com/kovidgoyal/imaging v1.6.4
1717
github.com/leporo/sqlf v1.4.0
1818
github.com/lithammer/shortuuid/v4 v4.2.0
1919
github.com/mneis/go-telnet v0.0.0-20221017141824-6f643e477c62
2020
github.com/rqlite/gorqlite v0.0.0-20250128004930-114c7828b55a
2121
github.com/sirupsen/logrus v1.9.3
22-
github.com/spf13/cobra v1.8.1
22+
github.com/spf13/cobra v1.9.0
2323
github.com/spf13/pflag v1.0.6
2424
github.com/tg123/go-htpasswd v1.2.3
2525
github.com/vanng822/go-premailer v1.23.0
26-
golang.org/x/net v0.34.0
26+
golang.org/x/net v0.35.0
2727
golang.org/x/text v0.22.0
2828
golang.org/x/time v0.10.0
2929
gopkg.in/yaml.v3 v3.0.1
30-
modernc.org/sqlite v1.34.5
30+
modernc.org/sqlite v1.35.0
3131
)
3232

3333
require (
@@ -53,11 +53,11 @@ require (
5353
github.com/valyala/bytebufferpool v1.0.0 // indirect
5454
github.com/vanng822/css v1.0.1 // indirect
5555
golang.org/x/crypto v0.33.0 // indirect
56-
golang.org/x/exp v0.0.0-20250207012021-f9890c6ad9f3 // indirect
56+
golang.org/x/exp v0.0.0-20250215185904-eff6e970281f // indirect
5757
golang.org/x/image v0.24.0 // indirect
5858
golang.org/x/sys v0.30.0 // indirect
5959
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
60-
modernc.org/libc v1.61.12 // indirect
60+
modernc.org/libc v1.61.13 // indirect
6161
modernc.org/mathutil v1.7.1 // indirect
6262
modernc.org/memory v1.8.2 // indirect
6363
)

go.sum

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
github.com/GehirnInc/crypt v0.0.0-20230320061759-8cc1b52080c5 h1:IEjq88XO4PuBDcvmjQJcQGg+w+UaafSy8G5Kcb5tBhI=
22
github.com/GehirnInc/crypt v0.0.0-20230320061759-8cc1b52080c5/go.mod h1:exZ0C/1emQJAw5tHOaUDyY1ycttqBAPcxuzf7QbY6ec=
33
github.com/PuerkitoBio/goquery v1.9.2/go.mod h1:GHPCaP0ODyyxqcNoFGYlAprUFH81NuRPd0GX3Zu2Mvk=
4-
github.com/PuerkitoBio/goquery v1.10.1 h1:Y8JGYUkXWTGRB6Ars3+j3kN0xg1YqqlwvdTV8WTFQcU=
5-
github.com/PuerkitoBio/goquery v1.10.1/go.mod h1:IYiHrOMps66ag56LEH7QYDDupKXyo5A8qrjIx3ZtujY=
4+
github.com/PuerkitoBio/goquery v1.10.2 h1:7fh2BdHcG6VFZsK7toXBT/Bh1z5Wmy8Q9MV9HqT2AM8=
5+
github.com/PuerkitoBio/goquery v1.10.2/go.mod h1:0guWGjcLu9AYC7C1GHnpysHy056u9aEkUHwhdnePMCU=
66
github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
77
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
88
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
@@ -12,7 +12,7 @@ github.com/axllent/semver v0.0.1 h1:QqF+KSGxgj8QZzSXAvKFqjGWE5792ksOnQhludToK8E=
1212
github.com/axllent/semver v0.0.1/go.mod h1:2xSPzvG8n9mRfdtxSvWvfTfQGWfHsMsHO1iZnKATMSc=
1313
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a h1:MISbI8sU/PSK/ztvmWKFcI7UGb5/HQT7B+i3a2myKgI=
1414
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a/go.mod h1:2GxOXOlEPAMFPfp014mK1SWq8G8BN8o7/dfYqJrVGn8=
15-
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
15+
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
1616
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
1717
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1818
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -45,8 +45,8 @@ github.com/jhillyerd/enmime v1.3.0 h1:LV5kzfLidiOr8qRGIpYYmUZCnhrPbcFAnAFUnWn99r
4545
github.com/jhillyerd/enmime v1.3.0/go.mod h1:6c6jg5HdRRV2FtvVL69LjiX1M8oE0xDX9VEhV3oy4gs=
4646
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
4747
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
48-
github.com/kovidgoyal/imaging v1.6.3 h1:iNPpv7ygiaB/NOztc6APMT7yr9UwBS+rOZwIbAdtyY8=
49-
github.com/kovidgoyal/imaging v1.6.3/go.mod h1:sHvcLOOVhJuto2IoNdPLEqnAUoL5ZfHEF0PpNH+882g=
48+
github.com/kovidgoyal/imaging v1.6.4 h1:K0idhRPXnRrJBKnBYcTfI1HTWSNDeAn7hYDvf9I0dCk=
49+
github.com/kovidgoyal/imaging v1.6.4/go.mod h1:bEIgsaZmXlvFfkv/CUxr9rJook6AQkJnpB5EPosRfRY=
5050
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
5151
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
5252
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
@@ -92,9 +92,8 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
9292
github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4/go.mod h1:C1a7PQSMz9NShzorzCiG2fk9+xuCgLkPeCvMHYR2OWg=
9393
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
9494
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
95-
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
96-
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
97-
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
95+
github.com/spf13/cobra v1.9.0 h1:Py5fIuq/lJsRYxcxfOtsJqpmwJWCMOUy2tMJYV8TNHE=
96+
github.com/spf13/cobra v1.9.0/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
9897
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
9998
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
10099
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo=
@@ -131,17 +130,17 @@ golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ss
131130
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
132131
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
133132
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
134-
golang.org/x/exp v0.0.0-20250207012021-f9890c6ad9f3 h1:qNgPs5exUA+G0C96DrPwNrvLSj7GT/9D+3WMWUcUg34=
135-
golang.org/x/exp v0.0.0-20250207012021-f9890c6ad9f3/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
133+
golang.org/x/exp v0.0.0-20250215185904-eff6e970281f h1:oFMYAjX0867ZD2jcNiLBrI9BdpmEkvPyi5YrBGXbamg=
134+
golang.org/x/exp v0.0.0-20250215185904-eff6e970281f/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk=
136135
golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ=
137136
golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8=
138137
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
139138
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
140139
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
141140
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
142141
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
143-
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
144-
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
142+
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
143+
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
145144
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
146145
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
147146
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
@@ -153,8 +152,9 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
153152
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
154153
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
155154
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
156-
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
157155
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
156+
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
157+
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
158158
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
159159
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
160160
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -215,8 +215,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
215215
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
216216
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
217217
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
218-
golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
219-
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
218+
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
219+
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
220220
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
221221
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
222222
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -234,8 +234,8 @@ modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
234234
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
235235
modernc.org/gc/v2 v2.6.3 h1:aJVhcqAte49LF+mGveZ5KPlsp4tdGdAOT4sipJXADjw=
236236
modernc.org/gc/v2 v2.6.3/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
237-
modernc.org/libc v1.61.12 h1:Fsnh0A7XLXylYNwIOJmKux9PhnfrIvMaMnjuyJ1t/f4=
238-
modernc.org/libc v1.61.12/go.mod h1:8F/uJWL/3nNil0Lgt1Dpz+GgkApWh04N3el3hxJcA6E=
237+
modernc.org/libc v1.61.13 h1:3LRd6ZO1ezsFiX1y+bHd1ipyEHIJKvuprv0sLTBwLW8=
238+
modernc.org/libc v1.61.13/go.mod h1:8F/uJWL/3nNil0Lgt1Dpz+GgkApWh04N3el3hxJcA6E=
239239
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
240240
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
241241
modernc.org/memory v1.8.2 h1:cL9L4bcoAObu4NkxOlKWBWtNHIsnnACGF/TbqQ6sbcI=
@@ -244,8 +244,8 @@ modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
244244
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
245245
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
246246
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
247-
modernc.org/sqlite v1.34.5 h1:Bb6SR13/fjp15jt70CL4f18JIN7p7dnMExd+UFnF15g=
248-
modernc.org/sqlite v1.34.5/go.mod h1:YLuNmX9NKs8wRNK2ko1LW1NGYcc9FkBO69JOt1AR9JE=
247+
modernc.org/sqlite v1.35.0 h1:yQps4fegMnZFdphtzlfQTCNBWtS0CZv48pRpW3RFHRw=
248+
modernc.org/sqlite v1.35.0/go.mod h1:9cr2sicr7jIaWTBKQmAxQLfBv9LL0su4ZTEV+utt3ic=
249249
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
250250
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
251251
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=

internal/dump/dump.go

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
// Package dump is used to export all messages from mailpit into a directory
2+
package dump
3+
4+
import (
5+
"encoding/json"
6+
"errors"
7+
"io"
8+
"net/http"
9+
"os"
10+
"path"
11+
"regexp"
12+
"strings"
13+
14+
"github.com/axllent/mailpit/config"
15+
"github.com/axllent/mailpit/internal/logger"
16+
"github.com/axllent/mailpit/internal/storage"
17+
"github.com/axllent/mailpit/internal/tools"
18+
"github.com/axllent/mailpit/server/apiv1"
19+
)
20+
21+
var (
22+
linkRe = regexp.MustCompile(`(?i)^https?:\/\/`)
23+
24+
outDir string
25+
26+
// Base URL of mailpit instance
27+
base string
28+
29+
// URL is the base URL of a remove Mailpit instance
30+
URL string
31+
32+
summary = []storage.MessageSummary{}
33+
)
34+
35+
// Sync will sync all messages from the specified database or API to the specified output directory
36+
func Sync(d string) error {
37+
38+
outDir = path.Clean(d)
39+
40+
if URL != "" {
41+
if !linkRe.MatchString(URL) {
42+
return errors.New("Invalid URL")
43+
}
44+
45+
base = strings.TrimRight(URL, "/") + "/"
46+
}
47+
48+
if base == "" && config.Database == "" {
49+
return errors.New("No database or API URL specified")
50+
}
51+
52+
if !tools.IsDir(outDir) {
53+
if err := os.MkdirAll(outDir, 0755); err != nil {
54+
return err
55+
}
56+
}
57+
58+
if err := loadIDs(); err != nil {
59+
return err
60+
}
61+
62+
if err := saveMessages(); err != nil {
63+
return err
64+
}
65+
66+
return nil
67+
}
68+
69+
// LoadIDs will load all message IDs from the specified database or API
70+
func loadIDs() error {
71+
if base != "" {
72+
// remote
73+
logger.Log().Debugf("Fetching messages summary from %s", base)
74+
res, err := http.Get(base + "api/v1/messages?limit=0")
75+
76+
if err != nil {
77+
return err
78+
}
79+
80+
body, err := io.ReadAll(res.Body)
81+
82+
if err != nil {
83+
return err
84+
}
85+
86+
var data apiv1.MessagesSummary
87+
if err := json.Unmarshal(body, &data); err != nil {
88+
return err
89+
}
90+
91+
summary = data.Messages
92+
93+
} else {
94+
// make sure the database isn't pruned while open
95+
config.MaxMessages = 0
96+
97+
var err error
98+
// local database
99+
if err = storage.InitDB(); err != nil {
100+
return err
101+
}
102+
103+
logger.Log().Debugf("Fetching messages summary from %s", config.Database)
104+
105+
summary, err = storage.List(0, 0, 0)
106+
if err != nil {
107+
return err
108+
}
109+
}
110+
111+
if len(summary) == 0 {
112+
return errors.New("No messages found")
113+
}
114+
115+
return nil
116+
}
117+
118+
func saveMessages() error {
119+
for _, m := range summary {
120+
out := path.Join(outDir, m.ID+".eml")
121+
122+
// skip if message exists
123+
if tools.IsFile(out) {
124+
continue
125+
}
126+
127+
var b []byte
128+
129+
if base != "" {
130+
res, err := http.Get(base + "api/v1/message/" + m.ID + "/raw")
131+
132+
if err != nil {
133+
logger.Log().Errorf("Error fetching message %s: %s", m.ID, err.Error())
134+
continue
135+
}
136+
137+
b, err = io.ReadAll(res.Body)
138+
139+
if err != nil {
140+
logger.Log().Errorf("Error fetching message %s: %s", m.ID, err.Error())
141+
continue
142+
}
143+
} else {
144+
var err error
145+
b, err = storage.GetMessageRaw(m.ID)
146+
if err != nil {
147+
logger.Log().Errorf("Error fetching message %s: %s", m.ID, err.Error())
148+
continue
149+
}
150+
}
151+
152+
if err := os.WriteFile(out, b, 0644); err != nil {
153+
logger.Log().Errorf("Error writing message %s: %s", m.ID, err.Error())
154+
continue
155+
}
156+
157+
_ = os.Chtimes(out, m.Created, m.Created)
158+
159+
logger.Log().Debugf("Saved message %s to %s", m.ID, out)
160+
}
161+
162+
return nil
163+
}

0 commit comments

Comments
 (0)