diff --git a/.vscode/settings.json b/.vscode/settings.json
index 09c563f..bedb688 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -26,6 +26,7 @@
"Mechs",
"navhtml",
"neostandard",
+ "nolint",
"popperjs",
"readyz",
"RSET",
diff --git a/internal/smtpd/chaos/chaos.go b/internal/smtpd/chaos/chaos.go
index d9994e0..e093b06 100644
--- a/internal/smtpd/chaos/chaos.go
+++ b/internal/smtpd/chaos/chaos.go
@@ -25,7 +25,8 @@ var (
)
// Triggers for the Chaos configuration
-// swagger:model Triggers
+//
+// swagger:model ChaosTriggers
type Triggers struct {
// Sender trigger to fail on From, Sender
Sender Trigger
@@ -36,7 +37,8 @@ type Triggers struct {
}
// Trigger for Chaos
-// swagger:model Trigger
+//
+// swagger:model ChaosTrigger
type Trigger struct {
// SMTP error code to return. The value must range from 400 to 599.
// required: true
diff --git a/server/apiv1/api.go b/server/apiv1/api.go
index 1008f14..718877c 100644
--- a/server/apiv1/api.go
+++ b/server/apiv1/api.go
@@ -35,9 +35,7 @@ func httpJSONError(w http.ResponseWriter, msg string) {
w.Header().Set("Referrer-Policy", "no-referrer")
w.Header().Set("Content-Security-Policy", config.ContentSecurityPolicy)
w.WriteHeader(http.StatusBadRequest)
- e := JSONErrorMessage{
- Error: msg,
- }
+ e := struct{ Error string }{Error: msg}
w.Header().Add("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(e); err != nil {
diff --git a/server/apiv1/application.go b/server/apiv1/application.go
index 5e8bad8..e7da7c1 100644
--- a/server/apiv1/application.go
+++ b/server/apiv1/application.go
@@ -10,16 +10,7 @@ import (
"github.com/axllent/mailpit/internal/stats"
)
-// Application information
-// swagger:response AppInfoResponse
-type appInfoResponse struct {
- // Application information
- //
- // in: body
- Body stats.AppInformation
-}
-
-// AppInfo returns some basic details about the running app, and latest release.
+// AppInfo returns some basic details about the running app including the latest release (unless disabled).
func AppInfo(w http.ResponseWriter, _ *http.Request) {
// swagger:route GET /api/v1/info application AppInformation
//
@@ -42,59 +33,9 @@ func AppInfo(w http.ResponseWriter, _ *http.Request) {
}
}
-// Response includes global web UI settings
-//
-// swagger:model WebUIConfiguration
-type webUIConfiguration struct {
- // Optional label to identify this Mailpit instance
- Label string
- // Message Relay information
- MessageRelay struct {
- // Whether message relaying (release) is enabled
- Enabled bool
- // The configured SMTP server address
- SMTPServer string
- // Enforced Return-Path (if set) for relay bounces
- ReturnPath string
- // Only allow relaying to these recipients (regex)
- AllowedRecipients string
- // Block relaying to these recipients (regex)
- BlockedRecipients string
- // Overrides the "From" address for all relayed messages
- OverrideFrom string
- // Preserve the original Message-IDs when relaying messages
- PreserveMessageIDs bool
-
- // DEPRECATED 2024/03/12
- // swagger:ignore
- RecipientAllowlist string
- }
-
- // Whether SpamAssassin is enabled
- SpamAssassin bool
-
- // Whether Chaos support is enabled at runtime
- ChaosEnabled bool
-
- // Whether messages with duplicate IDs are ignored
- DuplicatesIgnored bool
-
- // Whether the delete button should be hidden
- HideDeleteAllButton bool
-}
-
-// Web UI configuration response
-// swagger:response WebUIConfigurationResponse
-type webUIConfigurationResponse struct {
- // Web UI configuration settings
- //
- // in: body
- Body webUIConfiguration
-}
-
// WebUIConfig returns configuration settings for the web UI.
func WebUIConfig(w http.ResponseWriter, _ *http.Request) {
- // swagger:route GET /api/v1/webui application WebUIConfiguration
+ // swagger:route GET /api/v1/webui application WebUIConfigurationResponse
//
// # Get web UI configuration
//
@@ -110,29 +51,29 @@ func WebUIConfig(w http.ResponseWriter, _ *http.Request) {
// 200: WebUIConfigurationResponse
// 400: ErrorResponse
- conf := webUIConfiguration{}
+ conf := webUIConfigurationResponse{}
- conf.Label = config.Label
- conf.MessageRelay.Enabled = config.ReleaseEnabled
+ conf.Body.Label = config.Label
+ conf.Body.MessageRelay.Enabled = config.ReleaseEnabled
if config.ReleaseEnabled {
- conf.MessageRelay.SMTPServer = fmt.Sprintf("%s:%d", config.SMTPRelayConfig.Host, config.SMTPRelayConfig.Port)
- conf.MessageRelay.ReturnPath = config.SMTPRelayConfig.ReturnPath
- conf.MessageRelay.AllowedRecipients = config.SMTPRelayConfig.AllowedRecipients
- conf.MessageRelay.BlockedRecipients = config.SMTPRelayConfig.BlockedRecipients
- conf.MessageRelay.OverrideFrom = config.SMTPRelayConfig.OverrideFrom
- conf.MessageRelay.PreserveMessageIDs = config.SMTPRelayConfig.PreserveMessageIDs
+ conf.Body.MessageRelay.SMTPServer = fmt.Sprintf("%s:%d", config.SMTPRelayConfig.Host, config.SMTPRelayConfig.Port)
+ conf.Body.MessageRelay.ReturnPath = config.SMTPRelayConfig.ReturnPath
+ conf.Body.MessageRelay.AllowedRecipients = config.SMTPRelayConfig.AllowedRecipients
+ conf.Body.MessageRelay.BlockedRecipients = config.SMTPRelayConfig.BlockedRecipients
+ conf.Body.MessageRelay.OverrideFrom = config.SMTPRelayConfig.OverrideFrom
+ conf.Body.MessageRelay.PreserveMessageIDs = config.SMTPRelayConfig.PreserveMessageIDs
// DEPRECATED 2024/03/12
- conf.MessageRelay.RecipientAllowlist = config.SMTPRelayConfig.AllowedRecipients
+ conf.Body.MessageRelay.RecipientAllowlist = config.SMTPRelayConfig.AllowedRecipients
}
- conf.SpamAssassin = config.EnableSpamAssassin != ""
- conf.ChaosEnabled = chaos.Enabled
- conf.DuplicatesIgnored = config.IgnoreDuplicateIDs
- conf.HideDeleteAllButton = config.HideDeleteAllButton
+ conf.Body.SpamAssassin = config.EnableSpamAssassin != ""
+ conf.Body.ChaosEnabled = chaos.Enabled
+ conf.Body.DuplicatesIgnored = config.IgnoreDuplicateIDs
+ conf.Body.HideDeleteAllButton = config.HideDeleteAllButton
w.Header().Add("Content-Type", "application/json")
- if err := json.NewEncoder(w).Encode(conf); err != nil {
+ if err := json.NewEncoder(w).Encode(conf.Body); err != nil {
httpError(w, err.Error())
}
}
diff --git a/server/apiv1/chaos.go b/server/apiv1/chaos.go
index b538e8b..b7ac7fb 100644
--- a/server/apiv1/chaos.go
+++ b/server/apiv1/chaos.go
@@ -7,18 +7,6 @@ import (
"github.com/axllent/mailpit/internal/smtpd/chaos"
)
-// ChaosTriggers are the Chaos triggers
-type ChaosTriggers chaos.Triggers
-
-// Response for the Chaos triggers configuration
-// swagger:response ChaosResponse
-type chaosResponse struct {
- // The current Chaos triggers
- //
- // in: body
- Body ChaosTriggers
-}
-
// GetChaos returns the current Chaos triggers
func GetChaos(w http.ResponseWriter, _ *http.Request) {
// swagger:route GET /api/v1/chaos testing getChaos
@@ -50,12 +38,6 @@ func GetChaos(w http.ResponseWriter, _ *http.Request) {
}
}
-// swagger:parameters setChaosParams
-type setChaosParams struct {
- // in: body
- Body ChaosTriggers
-}
-
// SetChaos sets the Chaos configuration.
func SetChaos(w http.ResponseWriter, r *http.Request) {
// swagger:route PUT /api/v1/chaos testing setChaosParams
diff --git a/server/apiv1/message.go b/server/apiv1/message.go
index 455876b..c747120 100644
--- a/server/apiv1/message.go
+++ b/server/apiv1/message.go
@@ -11,15 +11,6 @@ import (
"github.com/gorilla/mux"
)
-// swagger:parameters GetMessageParams
-type getMessageParams struct {
- // Message database ID or "latest"
- //
- // in: path
- // required: true
- ID string
-}
-
// GetMessage (method: GET) returns the Message as JSON
func GetMessage(w http.ResponseWriter, r *http.Request) {
// swagger:route GET /api/v1/message/{ID} message GetMessageParams
@@ -66,19 +57,6 @@ func GetMessage(w http.ResponseWriter, r *http.Request) {
}
}
-// swagger:parameters GetHeadersParams
-type getHeadersParams struct {
- // Message database ID or "latest"
- //
- // in: path
- // required: true
- ID string
-}
-
-// Message headers
-// swagger:model MessageHeadersResponse
-type messageHeaders map[string][]string
-
// GetHeaders (method: GET) returns the message headers as JSON
func GetHeaders(w http.ResponseWriter, r *http.Request) {
// swagger:route GET /api/v1/message/{ID}/headers message GetHeadersParams
@@ -132,21 +110,6 @@ func GetHeaders(w http.ResponseWriter, r *http.Request) {
}
}
-// swagger:parameters AttachmentParams
-type attachmentParams struct {
- // Message database ID or "latest"
- //
- // in: path
- // required: true
- ID string
-
- // Attachment part ID
- //
- // in: path
- // required: true
- PartID string
-}
-
// DownloadAttachment (method: GET) returns the attachment data
func DownloadAttachment(w http.ResponseWriter, r *http.Request) {
// swagger:route GET /api/v1/message/{ID}/part/{PartID} message AttachmentParams
@@ -199,15 +162,6 @@ func DownloadAttachment(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write(a.Content)
}
-// swagger:parameters DownloadRawParams
-type downloadRawParams struct {
- // Message database ID or "latest"
- //
- // in: path
- // required: true
- ID string
-}
-
// DownloadRaw (method: GET) returns the full email source as plain text
func DownloadRaw(w http.ResponseWriter, r *http.Request) {
// swagger:route GET /api/v1/message/{ID}/raw message DownloadRawParams
diff --git a/server/apiv1/messages.go b/server/apiv1/messages.go
index 9832941..48009cc 100644
--- a/server/apiv1/messages.go
+++ b/server/apiv1/messages.go
@@ -8,35 +8,6 @@ import (
"github.com/axllent/mailpit/internal/storage"
)
-// swagger:parameters GetMessagesParams
-type getMessagesParams struct {
- // Pagination offset
- //
- // in: query
- // name: start
- // required: false
- // default: 0
- // type: integer
- Start int `json:"start"`
-
- // Limit number of results
- //
- // in: query
- // name: limit
- // required: false
- // default: 50
- // type: integer
- Limit int `json:"limit"`
-}
-
-// Summary of messages
-// swagger:response MessagesSummaryResponse
-type messagesSummaryResponse struct {
- // The messages summary
- // in: body
- Body MessagesSummary
-}
-
// MessagesSummary is a summary of a list of messages
type MessagesSummary struct {
// Total number of messages in mailbox
@@ -111,39 +82,6 @@ func GetMessages(w http.ResponseWriter, r *http.Request) {
}
}
-// swagger:parameters SetReadStatusParams
-type setReadStatusParams struct {
- // in: body
- Body struct {
- // Read status
- //
- // required: false
- // default: false
- // example: true
- Read bool
-
- // Optional array of message database IDs
- //
- // required: false
- // default: []
- // example: ["4oRBnPtCXgAqZniRhzLNmS", "hXayS6wnCgNnt6aFTvmOF6"]
- IDs []string
-
- // Optional messages matching a search
- //
- // required: false
- // example: tag:backups
- Search string
- }
-
- // Optional [timezone identifier](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) used only for `before:` & `after:` searches (eg: "Pacific/Auckland").
- //
- // in: query
- // required: false
- // type string
- TZ string `json:"tz"`
-}
-
// SetReadStatus (method: PUT) will update the status to Read/Unread for all provided IDs.
func SetReadStatus(w http.ResponseWriter, r *http.Request) {
// swagger:route PUT /api/v1/messages messages SetReadStatusParams
@@ -225,19 +163,6 @@ func SetReadStatus(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte("ok"))
}
-// swagger:parameters DeleteMessagesParams
-type deleteMessagesParams struct {
- // Delete request
- // in: body
- Body struct {
- // Array of message database IDs
- //
- // required: false
- // example: ["4oRBnPtCXgAqZniRhzLNmS", "hXayS6wnCgNnt6aFTvmOF6"]
- IDs []string
- }
-}
-
// DeleteMessages (method: DELETE) deletes all messages matching IDS.
func DeleteMessages(w http.ResponseWriter, r *http.Request) {
// swagger:route DELETE /api/v1/messages messages DeleteMessagesParams
@@ -279,39 +204,6 @@ func DeleteMessages(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte("ok"))
}
-// swagger:parameters SearchParams
-type searchParams struct {
- // Search query
- //
- // in: query
- // required: true
- // type: string
- Query string `json:"query"`
-
- // Pagination offset
- //
- // in: query
- // required: false
- // default: 0
- // type integer
- Start string `json:"start"`
-
- // Limit results
- //
- // in: query
- // required: false
- // default: 50
- // type integer
- Limit string `json:"limit"`
-
- // Optional [timezone identifier](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) used only for `before:` & `after:` searches (eg: "Pacific/Auckland").
- //
- // in: query
- // required: false
- // type string
- TZ string `json:"tz"`
-}
-
// Search returns the latest messages as JSON
func Search(w http.ResponseWriter, r *http.Request) {
// swagger:route GET /api/v1/search messages SearchParams
@@ -369,23 +261,6 @@ func Search(w http.ResponseWriter, r *http.Request) {
}
}
-// swagger:parameters DeleteSearchParams
-type deleteSearchParams struct {
- // Search query
- //
- // in: query
- // required: true
- // type: string
- Query string `json:"query"`
-
- // [Timezone identifier](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) used only for `before:` & `after:` searches (eg: "Pacific/Auckland").
- //
- // in: query
- // required: false
- // type string
- TZ string `json:"tz"`
-}
-
// DeleteSearch will delete all messages matching a search
func DeleteSearch(w http.ResponseWriter, r *http.Request) {
// swagger:route DELETE /api/v1/search messages DeleteSearchParams
diff --git a/server/apiv1/other.go b/server/apiv1/other.go
index ed77ff9..3b908e5 100644
--- a/server/apiv1/other.go
+++ b/server/apiv1/other.go
@@ -15,19 +15,6 @@ import (
"github.com/jhillyerd/enmime/v2"
)
-// swagger:parameters HTMLCheckParams
-type htmlCheckParams struct {
- // Message database ID or "latest"
- //
- // in: path
- // description: Message database ID or "latest"
- // required: true
- ID string
-}
-
-// HTMLCheckResponse summary response
-type HTMLCheckResponse = htmlcheck.Response
-
// HTMLCheck returns a summary of the HTML client support
func HTMLCheck(w http.ResponseWriter, r *http.Request) {
// swagger:route GET /api/v1/message/{ID}/html-check other HTMLCheckParams
@@ -93,25 +80,6 @@ func HTMLCheck(w http.ResponseWriter, r *http.Request) {
}
}
-// swagger:parameters LinkCheckParams
-type linkCheckParams struct {
- // Message database ID or "latest"
- //
- // in: path
- // required: true
- ID string
-
- // Follow redirects
- //
- // in: query
- // required: false
- // default: false
- Follow string `json:"follow"`
-}
-
-// LinkCheckResponse summary response
-type LinkCheckResponse = linkcheck.Response
-
// LinkCheck returns a summary of links in the email
func LinkCheck(w http.ResponseWriter, r *http.Request) {
// swagger:route GET /api/v1/message/{ID}/link-check other LinkCheckParams
@@ -170,18 +138,6 @@ func LinkCheck(w http.ResponseWriter, r *http.Request) {
}
}
-// swagger:parameters SpamAssassinCheckParams
-type spamAssassinCheckParams struct {
- // Message database ID or "latest"
- //
- // in: path
- // required: true
- ID string
-}
-
-// SpamAssassinResponse summary response
-type SpamAssassinResponse = spamassassin.Result
-
// SpamAssassinCheck returns a summary of SpamAssassin results (if enabled)
func SpamAssassinCheck(w http.ResponseWriter, r *http.Request) {
// swagger:route GET /api/v1/message/{ID}/sa-check other SpamAssassinCheckParams
diff --git a/server/apiv1/release.go b/server/apiv1/release.go
index bc7eeb8..f2c8e03 100644
--- a/server/apiv1/release.go
+++ b/server/apiv1/release.go
@@ -17,25 +17,6 @@ import (
"github.com/lithammer/shortuuid/v4"
)
-// swagger:parameters ReleaseMessageParams
-type releaseMessageParams struct {
- // Message database ID
- //
- // in: path
- // description: Message database ID
- // required: true
- ID string
-
- // in: body
- Body struct {
- // Array of email addresses to relay the message to
- //
- // required: true
- // example: ["user1@example.com", "user2@example.com"]
- To []string
- }
-}
-
// 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 ReleaseMessageParams
diff --git a/server/apiv1/send.go b/server/apiv1/send.go
index f945b5a..0d601a4 100644
--- a/server/apiv1/send.go
+++ b/server/apiv1/send.go
@@ -17,130 +17,6 @@ import (
"github.com/jhillyerd/enmime/v2"
)
-// swagger:parameters SendMessageParams
-type sendMessageParams struct {
- // in: body
- Body *SendRequest
-}
-
-// SendRequest to send a message via HTTP
-// swagger:model SendRequest
-type SendRequest struct {
- // "From" recipient
- // required: true
- From struct {
- // Optional name
- // example: John Doe
- Name string
- // Email address
- // example: john@example.com
- // required: true
- Email string
- }
-
- // "To" recipients
- To []struct {
- // Optional name
- // example: Jane Doe
- Name string
- // Email address
- // example: jane@example.com
- // required: true
- Email string
- }
-
- // Cc recipients
- Cc []struct {
- // Optional name
- // example: Manager
- Name string
- // Email address
- // example: manager@example.com
- // required: true
- Email string
- }
-
- // Bcc recipients email addresses only
- // example: ["jack@example.com"]
- Bcc []string
-
- // Optional Reply-To recipients
- ReplyTo []struct {
- // Optional name
- // example: Secretary
- Name string
- // Email address
- // example: secretary@example.com
- // required: true
- Email string
- }
-
- // Subject
- // example: Mailpit message via the HTTP API
- Subject string
-
- // Message body (text)
- // example: Mailpit is awesome!
- Text string
-
- // Message body (HTML)
- // example:
Mailpit is awesome!

- HTML string
-
- // Attachments
- Attachments []struct {
- // Base64-encoded string of the file content
- // required: true
- // example: iVBORw0KGgoAAAANSUhEUgAAAEEAAAA8CAMAAAAOlSdoAAAACXBIWXMAAAHrAAAB6wGM2bZBAAAAS1BMVEVHcEwRfnUkZ2gAt4UsSF8At4UtSV4At4YsSV4At4YsSV8At4YsSV4At4YsSV4sSV4At4YsSV4At4YtSV4At4YsSV4At4YtSV8At4YsUWYNAAAAGHRSTlMAAwoXGiktRE5dbnd7kpOlr7zJ0d3h8PD8PCSRAAACWUlEQVR42pXT4ZaqIBSG4W9rhqQYocG+/ys9Y0Z0Br+x3j8zaxUPewFh65K+7yrIMeIY4MT3wPfEJCidKXEMnLaVkxDiELiMz4WEOAZSFghxBIypCOlKiAMgXfIqTnBgSm8CIQ6BImxEUxEckClVQiHGj4Ba4AQHikAIClwTE9KtIghAhUJwoLkmLnCiAHJLRKgIMsEtVUKbBUIwoAg2C4QgQBE6l4VCnApBgSKYLLApCnCa0+96AEMW2BQcmC+Pr3nfp7o5Exy49gIADcIqUELGfeA+bp93LmAJp8QJoEcN3C7NY3sbVANixMyI0nku20/n5/ZRf3KI2k6JEDWQtxcbdGuAqu3TAXG+/799Oyyas1B1MnMiA+XyxHp9q0PUKGPiRAau1fZbLRZV09wZcT8/gHk8QQAxXn8VgaDqcUmU6O/r28nbVwXAqca2mRNtPAF5+zoP2MeN9Fy4NgC6RfcbgE7XITBRYTtOE3U3C2DVff7pk+PkUxgAbvtnPXJaD6DxulMLwOhPS/M3MQkgg1ZFrIXnmfaZoOfpKiFgzeZD/WuKqQEGrfJYkyWf6vlG3xUgTuscnkNkQsb599q124kdpMUjCa/XARHs1gZymVtGt3wLkiFv8rUgTxitYCex5EVGec0Y9VmoDTFBSQte2TfXGXlf7hbdaUM9Sk7fisEN9qfBBTK+FZcvM9fQSdkl2vj4W2oX/bRogO3XasiNH7R0eW7fgRM834ImTg+Lg6BEnx4vz81rhr+MYPBBQg1v8GndEOrthxaCTxNAOut8WKLGZQl+MPz88Q9tAO/hVuSeqQAAAABJRU5ErkJggg==
- Content string
- // Filename
- // required: true
- // example: mailpit.png
- Filename string
- // Optional Content Type for the the attachment.
- // If this field is not set (or empty) then the content type is automatically detected.
- // required: false
- // example: image/png
- ContentType string
- // Optional Content-ID (`cid`) for attachment.
- // If this field is set then the file is attached inline.
- // required: false
- // example: mailpit-logo
- ContentID string
- }
-
- // Mailpit tags
- // example: ["Tag 1","Tag 2"]
- Tags []string
-
- // Optional headers in {"key":"value"} format
- // example: {"X-IP":"1.2.3.4"}
- Headers map[string]string
-}
-
-// JSONErrorMessage struct
-type JSONErrorMessage struct {
- // Error message
- // example: invalid format
- Error string
-}
-
-// Confirmation message for HTTP send API
-// swagger:response sendMessageResponse
-type sendMessageResponse struct {
- // Response for sending messages via the HTTP API
- //
- // in: body
- Body SendMessageConfirmation
-}
-
-// SendMessageConfirmation struct
-type SendMessageConfirmation struct {
- // Database ID
- // example: iAfZVVe2UQfNSG5BAjgYwa
- ID string
-}
-
// SendMessageHandler handles HTTP requests to send a new message
func SendMessageHandler(w http.ResponseWriter, r *http.Request) {
// swagger:route POST /api/v1/send message SendMessageParams
@@ -158,8 +34,8 @@ func SendMessageHandler(w http.ResponseWriter, r *http.Request) {
// Schemes: http, https
//
// Responses:
- // 200: sendMessageResponse
- // 400: jsonErrorResponse
+ // 200: SendMessageResponse
+ // 400: JSONErrorResponse
if config.DemoMode {
httpJSONError(w, "this functionality has been disabled for demonstration purposes")
@@ -168,9 +44,9 @@ func SendMessageHandler(w http.ResponseWriter, r *http.Request) {
decoder := json.NewDecoder(r.Body)
- data := SendRequest{}
+ data := sendMessageParams{}
- if err := decoder.Decode(&data); err != nil {
+ if err := decoder.Decode(&data.Body); err != nil {
httpJSONError(w, err.Error())
return
}
@@ -188,14 +64,14 @@ func SendMessageHandler(w http.ResponseWriter, r *http.Request) {
}
w.Header().Add("Content-Type", "application/json")
- if err := json.NewEncoder(w).Encode(SendMessageConfirmation{ID: id}); err != nil {
+ if err := json.NewEncoder(w).Encode(struct{ ID string }{ID: id}); err != nil {
httpError(w, err.Error())
}
}
// Send will validate the message structure and attempt to send to Mailpit.
// It returns a sending summary or an error.
-func (d SendRequest) Send(remoteAddr string, httpAuthUser *string) (string, error) {
+func (d sendMessageParams) Send(remoteAddr string, httpAuthUser *string) (string, error) {
ip, _, err := net.SplitHostPort(remoteAddr)
if err != nil {
return "", fmt.Errorf("error parsing request RemoteAddr: %s", err.Error())
@@ -206,16 +82,16 @@ func (d SendRequest) Send(remoteAddr string, httpAuthUser *string) (string, erro
addresses := []string{}
msg := enmime.Builder().
- From(d.From.Name, d.From.Email).
- Subject(d.Subject).
- Text([]byte(d.Text))
+ From(d.Body.From.Name, d.Body.From.Email).
+ Subject(d.Body.Subject).
+ Text([]byte(d.Body.Text))
- if d.HTML != "" {
- msg = msg.HTML([]byte(d.HTML))
+ if d.Body.HTML != "" {
+ msg = msg.HTML([]byte(d.Body.HTML))
}
- if len(d.To) > 0 {
- for _, a := range d.To {
+ if len(d.Body.To) > 0 {
+ for _, a := range d.Body.To {
if _, err := mail.ParseAddress(a.Email); err == nil {
msg = msg.To(a.Name, a.Email)
addresses = append(addresses, a.Email)
@@ -225,8 +101,8 @@ func (d SendRequest) Send(remoteAddr string, httpAuthUser *string) (string, erro
}
}
- if len(d.Cc) > 0 {
- for _, a := range d.Cc {
+ if len(d.Body.Cc) > 0 {
+ for _, a := range d.Body.Cc {
if _, err := mail.ParseAddress(a.Email); err == nil {
msg = msg.CC(a.Name, a.Email)
addresses = append(addresses, a.Email)
@@ -236,8 +112,8 @@ func (d SendRequest) Send(remoteAddr string, httpAuthUser *string) (string, erro
}
}
- if len(d.Bcc) > 0 {
- for _, e := range d.Bcc {
+ if len(d.Body.Bcc) > 0 {
+ for _, e := range d.Body.Bcc {
if _, err := mail.ParseAddress(e); err == nil {
msg = msg.BCC("", e)
addresses = append(addresses, e)
@@ -247,8 +123,8 @@ func (d SendRequest) Send(remoteAddr string, httpAuthUser *string) (string, erro
}
}
- if len(d.ReplyTo) > 0 {
- for _, a := range d.ReplyTo {
+ if len(d.Body.ReplyTo) > 0 {
+ for _, a := range d.Body.ReplyTo {
if _, err := mail.ParseAddress(a.Email); err == nil {
msg = msg.ReplyTo(a.Name, a.Email)
} else {
@@ -259,13 +135,13 @@ func (d SendRequest) Send(remoteAddr string, httpAuthUser *string) (string, erro
restrictedHeaders := []string{"To", "From", "Cc", "Bcc", "Reply-To", "Date", "Subject", "Content-Type", "Mime-Version"}
- if len(d.Tags) > 0 {
- msg = msg.Header("X-Tags", strings.Join(d.Tags, ", "))
+ if len(d.Body.Tags) > 0 {
+ msg = msg.Header("X-Tags", strings.Join(d.Body.Tags, ", "))
restrictedHeaders = append(restrictedHeaders, "X-Tags")
}
- if len(d.Headers) > 0 {
- for k, v := range d.Headers {
+ if len(d.Body.Headers) > 0 {
+ for k, v := range d.Body.Headers {
// check header isn't in "restricted" headers
if tools.InArray(k, restrictedHeaders) {
return "", fmt.Errorf("cannot overwrite header: \"%s\"", k)
@@ -274,8 +150,8 @@ func (d SendRequest) Send(remoteAddr string, httpAuthUser *string) (string, erro
}
}
- if len(d.Attachments) > 0 {
- for _, a := range d.Attachments {
+ if len(d.Body.Attachments) > 0 {
+ for _, a := range d.Body.Attachments {
// workaround: split string because JS readAsDataURL() returns the base64 string
// with the mime type prefix eg: data:image/png;base64,
parts := strings.Split(a.Content, ",")
@@ -307,5 +183,5 @@ func (d SendRequest) Send(remoteAddr string, httpAuthUser *string) (string, erro
return "", fmt.Errorf("error building message: %s", err.Error())
}
- return smtpd.SaveToDatabase(ipAddr, d.From.Email, addresses, buff.Bytes(), httpAuthUser)
+ return smtpd.SaveToDatabase(ipAddr, d.Body.From.Email, addresses, buff.Bytes(), httpAuthUser)
}
diff --git a/server/apiv1/swagger.go b/server/apiv1/swagger.go
deleted file mode 100644
index b043db2..0000000
--- a/server/apiv1/swagger.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package apiv1
-
-// These structs are for the purpose of defining swagger HTTP parameters & responses
-
-// Binary data response which inherits the attachment's content type.
-// swagger:response BinaryResponse
-type binaryResponse string
-
-// Plain text response
-// swagger:response TextResponse
-type textResponse string
-
-// HTML response
-// swagger:response HTMLResponse
-type htmlResponse string
-
-// Server error will return with a 400 status code
-// with the error message in the body
-// swagger:response ErrorResponse
-type errorResponse string
-
-// Not found error will return a 404 status code
-// swagger:response NotFoundResponse
-type notFoundResponse string
-
-// Plain text "ok" response
-// swagger:response OKResponse
-type okResponse string
-
-// Plain JSON array response
-// swagger:response ArrayResponse
-type arrayResponse []string
-
-// JSON error response
-// swagger:response jsonErrorResponse
-type jsonErrorResponse struct {
- // A JSON-encoded error response
- //
- // in: body
- Body JSONErrorMessage
-}
diff --git a/server/apiv1/swaggerParams.go b/server/apiv1/swaggerParams.go
new file mode 100644
index 0000000..7bc3bb2
--- /dev/null
+++ b/server/apiv1/swaggerParams.go
@@ -0,0 +1,416 @@
+// Package apiv1 provides the API v1 endpoints for Mailpit.
+//
+// These structs are for the purpose of defining swagger HTTP parameters in go-swagger
+// in order to generate a spec file. They are lowercased to avoid exporting them as public types.
+//
+//nolint:unused
+package apiv1
+
+import "github.com/axllent/mailpit/internal/smtpd/chaos"
+
+// swagger:parameters setChaosParams
+type setChaosParams struct {
+ // in: body
+ Body chaos.Triggers
+}
+
+// swagger:parameters AttachmentParams
+type attachmentParams struct {
+ // Message database ID or "latest"
+ //
+ // in: path
+ // required: true
+ ID string
+
+ // Attachment part ID
+ //
+ // in: path
+ // required: true
+ PartID string
+}
+
+// swagger:parameters DownloadRawParams
+type downloadRawParams struct {
+ // Message database ID or "latest"
+ //
+ // in: path
+ // required: true
+ ID string
+}
+
+// swagger:parameters GetMessageParams
+type getMessageParams struct {
+ // Message database ID or "latest"
+ //
+ // in: path
+ // required: true
+ ID string
+}
+
+// swagger:parameters GetHeadersParams
+type getHeadersParams struct {
+ // Message database ID or "latest"
+ //
+ // in: path
+ // required: true
+ ID string
+}
+
+// swagger:parameters GetMessagesParams
+type getMessagesParams struct {
+ // Pagination offset
+ //
+ // in: query
+ // name: start
+ // required: false
+ // default: 0
+ // type: integer
+ Start int `json:"start"`
+
+ // Limit number of results
+ //
+ // in: query
+ // name: limit
+ // required: false
+ // default: 50
+ // type: integer
+ Limit int `json:"limit"`
+}
+
+// swagger:parameters SetReadStatusParams
+type setReadStatusParams struct {
+ // in: body
+ Body struct {
+ // Read status
+ //
+ // required: false
+ // default: false
+ // example: true
+ Read bool
+
+ // Optional array of message database IDs
+ //
+ // required: false
+ // default: []
+ // example: ["4oRBnPtCXgAqZniRhzLNmS", "hXayS6wnCgNnt6aFTvmOF6"]
+ IDs []string
+
+ // Optional messages matching a search
+ //
+ // required: false
+ // example: tag:backups
+ Search string
+ }
+
+ // Optional [timezone identifier](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) used only for `before:` & `after:` searches (eg: "Pacific/Auckland").
+ //
+ // in: query
+ // required: false
+ // type string
+ TZ string `json:"tz"`
+}
+
+// swagger:parameters DeleteMessagesParams
+type deleteMessagesParams struct {
+ // Delete request
+ // in: body
+ Body struct {
+ // Array of message database IDs
+ //
+ // required: false
+ // example: ["4oRBnPtCXgAqZniRhzLNmS", "hXayS6wnCgNnt6aFTvmOF6"]
+ IDs []string
+ }
+}
+
+// swagger:parameters SearchParams
+type searchParams struct {
+ // Search query
+ //
+ // in: query
+ // required: true
+ // type: string
+ Query string `json:"query"`
+
+ // Pagination offset
+ //
+ // in: query
+ // required: false
+ // default: 0
+ // type integer
+ Start string `json:"start"`
+
+ // Limit results
+ //
+ // in: query
+ // required: false
+ // default: 50
+ // type integer
+ Limit string `json:"limit"`
+
+ // Optional [timezone identifier](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) used only for `before:` & `after:` searches (eg: "Pacific/Auckland").
+ //
+ // in: query
+ // required: false
+ // type string
+ TZ string `json:"tz"`
+}
+
+// swagger:parameters DeleteSearchParams
+type deleteSearchParams struct {
+ // Search query
+ //
+ // in: query
+ // required: true
+ // type: string
+ Query string `json:"query"`
+
+ // [Timezone identifier](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) used only for `before:` & `after:` searches (eg: "Pacific/Auckland").
+ //
+ // in: query
+ // required: false
+ // type string
+ TZ string `json:"tz"`
+}
+
+// swagger:parameters HTMLCheckParams
+type htmlCheckParams struct {
+ // Message database ID or "latest"
+ //
+ // in: path
+ // description: Message database ID or "latest"
+ // required: true
+ ID string
+}
+
+// swagger:parameters LinkCheckParams
+type linkCheckParams struct {
+ // Message database ID or "latest"
+ //
+ // in: path
+ // required: true
+ ID string
+
+ // Follow redirects
+ //
+ // in: query
+ // required: false
+ // default: false
+ Follow string `json:"follow"`
+}
+
+// swagger:parameters ReleaseMessageParams
+type releaseMessageParams struct {
+ // Message database ID
+ //
+ // in: path
+ // description: Message database ID
+ // required: true
+ ID string
+
+ // in: body
+ Body struct {
+ // Array of email addresses to relay the message to
+ //
+ // required: true
+ // example: ["user1@example.com", "user2@example.com"]
+ To []string
+ }
+}
+
+// swagger:parameters SendMessageParams
+type sendMessageParams struct {
+ // in: body
+ // Body SendRequest
+ Body struct {
+ // "From" recipient
+ // required: true
+ From struct {
+ // Optional name
+ // example: John Doe
+ Name string
+ // Email address
+ // example: john@example.com
+ // required: true
+ Email string
+ }
+
+ // "To" recipients
+ To []struct {
+ // Optional name
+ // example: Jane Doe
+ Name string
+ // Email address
+ // example: jane@example.com
+ // required: true
+ Email string
+ }
+
+ // Cc recipients
+ Cc []struct {
+ // Optional name
+ // example: Manager
+ Name string
+ // Email address
+ // example: manager@example.com
+ // required: true
+ Email string
+ }
+
+ // Bcc recipients email addresses only
+ // example: ["jack@example.com"]
+ Bcc []string
+
+ // Optional Reply-To recipients
+ ReplyTo []struct {
+ // Optional name
+ // example: Secretary
+ Name string
+ // Email address
+ // example: secretary@example.com
+ // required: true
+ Email string
+ }
+
+ // Subject
+ // example: Mailpit message via the HTTP API
+ Subject string
+
+ // Message body (text)
+ // example: Mailpit is awesome!
+ Text string
+
+ // Message body (HTML)
+ // example: Mailpit is awesome!

+ HTML string
+
+ // Attachments
+ Attachments []struct {
+ // Base64-encoded string of the file content
+ // required: true
+ // example: iVBORw0KGgoAAAANSUhEUgAAAEEAAAA8CAMAAAAOlSdoAAAACXBIWXMAAAHrAAAB6wGM2bZBAAAAS1BMVEVHcEwRfnUkZ2gAt4UsSF8At4UtSV4At4YsSV4At4YsSV8At4YsSV4At4YsSV4sSV4At4YsSV4At4YtSV4At4YsSV4At4YtSV8At4YsUWYNAAAAGHRSTlMAAwoXGiktRE5dbnd7kpOlr7zJ0d3h8PD8PCSRAAACWUlEQVR42pXT4ZaqIBSG4W9rhqQYocG+/ys9Y0Z0Br+x3j8zaxUPewFh65K+7yrIMeIY4MT3wPfEJCidKXEMnLaVkxDiELiMz4WEOAZSFghxBIypCOlKiAMgXfIqTnBgSm8CIQ6BImxEUxEckClVQiHGj4Ba4AQHikAIClwTE9KtIghAhUJwoLkmLnCiAHJLRKgIMsEtVUKbBUIwoAg2C4QgQBE6l4VCnApBgSKYLLApCnCa0+96AEMW2BQcmC+Pr3nfp7o5Exy49gIADcIqUELGfeA+bp93LmAJp8QJoEcN3C7NY3sbVANixMyI0nku20/n5/ZRf3KI2k6JEDWQtxcbdGuAqu3TAXG+/799Oyyas1B1MnMiA+XyxHp9q0PUKGPiRAau1fZbLRZV09wZcT8/gHk8QQAxXn8VgaDqcUmU6O/r28nbVwXAqca2mRNtPAF5+zoP2MeN9Fy4NgC6RfcbgE7XITBRYTtOE3U3C2DVff7pk+PkUxgAbvtnPXJaD6DxulMLwOhPS/M3MQkgg1ZFrIXnmfaZoOfpKiFgzeZD/WuKqQEGrfJYkyWf6vlG3xUgTuscnkNkQsb599q124kdpMUjCa/XARHs1gZymVtGt3wLkiFv8rUgTxitYCex5EVGec0Y9VmoDTFBSQte2TfXGXlf7hbdaUM9Sk7fisEN9qfBBTK+FZcvM9fQSdkl2vj4W2oX/bRogO3XasiNH7R0eW7fgRM834ImTg+Lg6BEnx4vz81rhr+MYPBBQg1v8GndEOrthxaCTxNAOut8WKLGZQl+MPz88Q9tAO/hVuSeqQAAAABJRU5ErkJggg==
+ Content string
+ // Filename
+ // required: true
+ // example: mailpit.png
+ Filename string
+ // Optional Content Type for the the attachment.
+ // If this field is not set (or empty) then the content type is automatically detected.
+ // required: false
+ // example: image/png
+ ContentType string
+ // Optional Content-ID (`cid`) for attachment.
+ // If this field is set then the file is attached inline.
+ // required: false
+ // example: mailpit-logo
+ ContentID string
+ }
+
+ // Mailpit tags
+ // example: ["Tag 1","Tag 2"]
+ Tags []string
+
+ // Optional headers in {"key":"value"} format
+ // example: {"X-IP":"1.2.3.4"}
+ Headers map[string]string
+ }
+}
+
+// swagger:parameters SetTagsParams
+type setTagsParams struct {
+ // in: body
+ Body struct {
+ // Array of tag names to set
+ //
+ // required: true
+ // example: ["Tag 1", "Tag 2"]
+ Tags []string
+
+ // Array of message database IDs
+ //
+ // required: true
+ // example: ["4oRBnPtCXgAqZniRhzLNmS", "hXayS6wnCgNnt6aFTvmOF6"]
+ IDs []string
+ }
+}
+
+// swagger:parameters RenameTagParams
+type renameTagParams struct {
+ // The url-encoded tag name to rename
+ //
+ // in: path
+ // required: true
+ // type: string
+ Tag string
+
+ // in: body
+ Body struct {
+ // New name
+ //
+ // required: true
+ // example: New name
+ Name string
+ }
+}
+
+// swagger:parameters DeleteTagParams
+type deleteTagParams struct {
+ // The url-encoded tag name to delete
+ //
+ // in: path
+ // required: true
+ Tag string
+}
+
+// swagger:parameters GetMessageHTMLParams
+type getMessageHTMLParams struct {
+ // Message database ID or "latest"
+ //
+ // in: path
+ // required: true
+ ID string
+
+ // If this is route is to be embedded in an iframe, set embed to `1` in the URL to add `target="_blank"` and `rel="noreferrer noopener"` to all links.
+ //
+ // In addition, a small script will be added to the end of the document to post (postMessage()) the height of the document back to the parent window for optional iframe height resizing.
+ //
+ // Note that this will also *transform* the message into a full HTML document (if it isn't already), so this option is useful for viewing but not programmatic testing.
+ //
+ // in: query
+ // required: false
+ // type: string
+ Embed string `json:"embed"`
+}
+
+// swagger:parameters GetMessageTextParams
+type getMessageTextParams struct {
+ // Message database ID or "latest"
+ //
+ // in: path
+ // required: true
+ ID string
+}
+
+// swagger:parameters SpamAssassinCheckParams
+type spamAssassinCheckParams struct {
+ // Message database ID or "latest"
+ //
+ // in: path
+ // required: true
+ ID string
+}
+
+// swagger:parameters ThumbnailParams
+type thumbnailParams struct {
+ // Message database ID or "latest"
+ //
+ // in: path
+ // required: true
+ ID string
+
+ // Attachment part ID
+ //
+ // in: path
+ // required: true
+ PartID string
+}
diff --git a/server/apiv1/swaggerResponses.go b/server/apiv1/swaggerResponses.go
new file mode 100644
index 0000000..274653d
--- /dev/null
+++ b/server/apiv1/swaggerResponses.go
@@ -0,0 +1,142 @@
+// Package apiv1 provides the API v1 endpoints for Mailpit.
+//
+// These structs are for the purpose of defining swagger HTTP responses in go-swagger
+// in order to generate a spec file. They are lowercased to avoid exporting them as public types.
+//
+//nolint:unused
+package apiv1
+
+import (
+ "github.com/axllent/mailpit/internal/smtpd/chaos"
+ "github.com/axllent/mailpit/internal/stats"
+)
+
+// Binary data response which inherits the attachment's content type.
+// swagger:response BinaryResponse
+type binaryResponse string
+
+// Plain text response
+// swagger:response TextResponse
+type textResponse string
+
+// HTML response
+// swagger:response HTMLResponse
+type htmlResponse string
+
+// Server error will return with a 400 status code
+// with the error message in the body
+// swagger:response ErrorResponse
+type errorResponse string
+
+// Not found error will return a 404 status code
+// swagger:response NotFoundResponse
+type notFoundResponse string
+
+// Plain text "ok" response
+// swagger:response OKResponse
+type okResponse string
+
+// Plain JSON array response
+// swagger:response ArrayResponse
+type arrayResponse []string
+
+// JSON error response
+// swagger:response JSONErrorResponse
+type jsonErrorResponse struct {
+ // A JSON-encoded error response
+ //
+ // in: body
+ Body struct {
+ // Error message
+ // example: invalid format
+ Error string
+ }
+}
+
+// Web UI configuration response
+// swagger:response WebUIConfigurationResponse
+type webUIConfigurationResponse struct {
+ // Web UI configuration settings
+ //
+ // in: body
+ Body struct {
+ // Optional label to identify this Mailpit instance
+ Label string
+ // Message Relay information
+ MessageRelay struct {
+ // Whether message relaying (release) is enabled
+ Enabled bool
+ // The configured SMTP server address
+ SMTPServer string
+ // Enforced Return-Path (if set) for relay bounces
+ ReturnPath string
+ // Only allow relaying to these recipients (regex)
+ AllowedRecipients string
+ // Block relaying to these recipients (regex)
+ BlockedRecipients string
+ // Overrides the "From" address for all relayed messages
+ OverrideFrom string
+ // Preserve the original Message-IDs when relaying messages
+ PreserveMessageIDs bool
+
+ // DEPRECATED 2024/03/12
+ // swagger:ignore
+ RecipientAllowlist string
+ }
+
+ // Whether SpamAssassin is enabled
+ SpamAssassin bool
+
+ // Whether Chaos support is enabled at runtime
+ ChaosEnabled bool
+
+ // Whether messages with duplicate IDs are ignored
+ DuplicatesIgnored bool
+
+ // Whether the delete button should be hidden
+ HideDeleteAllButton bool
+ }
+}
+
+// Application information
+// swagger:response AppInfoResponse
+type appInfoResponse struct {
+ // Application information
+ //
+ // in: body
+ Body stats.AppInformation
+}
+
+// Response for the Chaos triggers configuration
+// swagger:response ChaosResponse
+type chaosResponse struct {
+ // The current Chaos triggers
+ //
+ // in: body
+ Body chaos.Triggers
+}
+
+// Message headers
+// swagger:model MessageHeadersResponse
+type messageHeadersResponse map[string][]string
+
+// Summary of messages
+// swagger:response MessagesSummaryResponse
+type messagesSummaryResponse struct {
+ // The messages summary
+ // in: body
+ Body MessagesSummary
+}
+
+// Confirmation message for HTTP send API
+// swagger:response SendMessageResponse
+type sendMessageResponse struct {
+ // Response for sending messages via the HTTP API
+ //
+ // in: body
+ Body struct {
+ // Database ID
+ // example: iAfZVVe2UQfNSG5BAjgYwa
+ ID string
+ }
+}
diff --git a/server/apiv1/tags.go b/server/apiv1/tags.go
index cd58c64..5c59cc6 100644
--- a/server/apiv1/tags.go
+++ b/server/apiv1/tags.go
@@ -32,24 +32,6 @@ func GetAllTags(w http.ResponseWriter, _ *http.Request) {
}
}
-// swagger:parameters SetTagsParams
-type setTagsParams struct {
- // in: body
- Body struct {
- // Array of tag names to set
- //
- // required: true
- // example: ["Tag 1", "Tag 2"]
- Tags []string
-
- // Array of message database IDs
- //
- // required: true
- // example: ["4oRBnPtCXgAqZniRhzLNmS", "hXayS6wnCgNnt6aFTvmOF6"]
- IDs []string
- }
-}
-
// SetMessageTags (method: PUT) will set the tags for all provided IDs
func SetMessageTags(w http.ResponseWriter, r *http.Request) {
// swagger:route PUT /api/v1/tags tags SetTagsParams
@@ -98,25 +80,6 @@ func SetMessageTags(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte("ok"))
}
-// swagger:parameters RenameTagParams
-type renameTagParams struct {
- // The url-encoded tag name to rename
- //
- // in: path
- // required: true
- // type: string
- Tag string
-
- // in: body
- Body struct {
- // New name
- //
- // required: true
- // example: New name
- Name string
- }
-}
-
// RenameTag (method: PUT) used to rename a tag
func RenameTag(w http.ResponseWriter, r *http.Request) {
// swagger:route PUT /api/v1/tags/{Tag} tags RenameTagParams
@@ -161,15 +124,6 @@ func RenameTag(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte("ok"))
}
-// swagger:parameters DeleteTagParams
-type deleteTagParams struct {
- // The url-encoded tag name to delete
- //
- // in: path
- // required: true
- Tag string
-}
-
// DeleteTag (method: DELETE) used to delete a tag
func DeleteTag(w http.ResponseWriter, r *http.Request) {
// swagger:route DELETE /api/v1/tags/{Tag} tags DeleteTagParams
diff --git a/server/apiv1/testing.go b/server/apiv1/testing.go
index 80db613..a9b255f 100644
--- a/server/apiv1/testing.go
+++ b/server/apiv1/testing.go
@@ -16,26 +16,6 @@ import (
"golang.org/x/net/html/atom"
)
-// swagger:parameters GetMessageHTMLParams
-type getMessageHTMLParams struct {
- // Message database ID or "latest"
- //
- // in: path
- // required: true
- ID string
-
- // If this is route is to be embedded in an iframe, set embed to `1` in the URL to add `target="_blank"` and `rel="noreferrer noopener"` to all links.
- //
- // In addition, a small script will be added to the end of the document to post (postMessage()) the height of the document back to the parent window for optional iframe height resizing.
- //
- // Note that this will also *transform* the message into a full HTML document (if it isn't already), so this option is useful for viewing but not programmatic testing.
- //
- // in: query
- // required: false
- // type: string
- Embed string `json:"embed"`
-}
-
// GetMessageHTML (method: GET) returns a rendered version of a message's HTML part
func GetMessageHTML(w http.ResponseWriter, r *http.Request) {
// swagger:route GET /view/{ID}.html testing GetMessageHTMLParams
@@ -123,15 +103,6 @@ func GetMessageHTML(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte(htmlStr))
}
-// swagger:parameters GetMessageTextParams
-type getMessageTextParams struct {
- // Message database ID or "latest"
- //
- // in: path
- // required: true
- ID string
-}
-
// GetMessageText (method: GET) returns a message's text part
func GetMessageText(w http.ResponseWriter, r *http.Request) {
// swagger:route GET /view/{ID}.txt testing GetMessageTextParams
diff --git a/server/apiv1/thumbnails.go b/server/apiv1/thumbnails.go
index 97920b5..af98206 100644
--- a/server/apiv1/thumbnails.go
+++ b/server/apiv1/thumbnails.go
@@ -22,21 +22,6 @@ var (
thumbHeight = 120
)
-// swagger:parameters ThumbnailParams
-type thumbnailParams struct {
- // Message database ID or "latest"
- //
- // in: path
- // required: true
- ID string
-
- // Attachment part ID
- //
- // in: path
- // required: true
- PartID string
-}
-
// Thumbnail returns a thumbnail image for an attachment (images only)
func Thumbnail(w http.ResponseWriter, r *http.Request) {
// swagger:route GET /api/v1/message/{ID}/part/{PartID}/thumb message ThumbnailParams
diff --git a/server/server_test.go b/server/server_test.go
index ccc3799..a4ee108 100644
--- a/server/server_test.go
+++ b/server/server_test.go
@@ -283,7 +283,9 @@ func TestAPIv1Send(t *testing.T) {
t.Errorf("Expected nil, received %s", err.Error())
}
- resp := apiv1.SendMessageConfirmation{}
+ resp := struct {
+ ID string
+ }{}
if err := json.Unmarshal(b, &resp); err != nil {
t.Error(err.Error())
diff --git a/server/ui/api/v1/swagger.json b/server/ui/api/v1/swagger.json
index c370deb..e5fc5fd 100644
--- a/server/ui/api/v1/swagger.json
+++ b/server/ui/api/v1/swagger.json
@@ -785,16 +785,185 @@
"name": "Body",
"in": "body",
"schema": {
- "$ref": "#/definitions/SendRequest"
+ "type": "object",
+ "required": [
+ "From"
+ ],
+ "properties": {
+ "Attachments": {
+ "description": "Attachments",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": [
+ "Content",
+ "Filename"
+ ],
+ "properties": {
+ "Content": {
+ "description": "Base64-encoded string of the file content",
+ "type": "string",
+ "example": "iVBORw0KGgoAAAANSUhEUgAAAEEAAAA8CAMAAAAOlSdoAAAACXBIWXMAAAHrAAAB6wGM2bZBAAAAS1BMVEVHcEwRfnUkZ2gAt4UsSF8At4UtSV4At4YsSV4At4YsSV8At4YsSV4At4YsSV4sSV4At4YsSV4At4YtSV4At4YsSV4At4YtSV8At4YsUWYNAAAAGHRSTlMAAwoXGiktRE5dbnd7kpOlr7zJ0d3h8PD8PCSRAAACWUlEQVR42pXT4ZaqIBSG4W9rhqQYocG+/ys9Y0Z0Br+x3j8zaxUPewFh65K+7yrIMeIY4MT3wPfEJCidKXEMnLaVkxDiELiMz4WEOAZSFghxBIypCOlKiAMgXfIqTnBgSm8CIQ6BImxEUxEckClVQiHGj4Ba4AQHikAIClwTE9KtIghAhUJwoLkmLnCiAHJLRKgIMsEtVUKbBUIwoAg2C4QgQBE6l4VCnApBgSKYLLApCnCa0+96AEMW2BQcmC+Pr3nfp7o5Exy49gIADcIqUELGfeA+bp93LmAJp8QJoEcN3C7NY3sbVANixMyI0nku20/n5/ZRf3KI2k6JEDWQtxcbdGuAqu3TAXG+/799Oyyas1B1MnMiA+XyxHp9q0PUKGPiRAau1fZbLRZV09wZcT8/gHk8QQAxXn8VgaDqcUmU6O/r28nbVwXAqca2mRNtPAF5+zoP2MeN9Fy4NgC6RfcbgE7XITBRYTtOE3U3C2DVff7pk+PkUxgAbvtnPXJaD6DxulMLwOhPS/M3MQkgg1ZFrIXnmfaZoOfpKiFgzeZD/WuKqQEGrfJYkyWf6vlG3xUgTuscnkNkQsb599q124kdpMUjCa/XARHs1gZymVtGt3wLkiFv8rUgTxitYCex5EVGec0Y9VmoDTFBSQte2TfXGXlf7hbdaUM9Sk7fisEN9qfBBTK+FZcvM9fQSdkl2vj4W2oX/bRogO3XasiNH7R0eW7fgRM834ImTg+Lg6BEnx4vz81rhr+MYPBBQg1v8GndEOrthxaCTxNAOut8WKLGZQl+MPz88Q9tAO/hVuSeqQAAAABJRU5ErkJggg=="
+ },
+ "ContentID": {
+ "description": "Optional Content-ID (`cid`) for attachment.\nIf this field is set then the file is attached inline.",
+ "type": "string",
+ "example": "mailpit-logo"
+ },
+ "ContentType": {
+ "description": "Optional Content Type for the the attachment.\nIf this field is not set (or empty) then the content type is automatically detected.",
+ "type": "string",
+ "example": "image/png"
+ },
+ "Filename": {
+ "description": "Filename",
+ "type": "string",
+ "example": "mailpit.png"
+ }
+ }
+ }
+ },
+ "Bcc": {
+ "description": "Bcc recipients email addresses only",
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "example": [
+ "jack@example.com"
+ ]
+ },
+ "Cc": {
+ "description": "Cc recipients",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": [
+ "Email"
+ ],
+ "properties": {
+ "Email": {
+ "description": "Email address",
+ "type": "string",
+ "example": "manager@example.com"
+ },
+ "Name": {
+ "description": "Optional name",
+ "type": "string",
+ "example": "Manager"
+ }
+ }
+ }
+ },
+ "From": {
+ "description": "\"From\" recipient",
+ "type": "object",
+ "required": [
+ "Email"
+ ],
+ "properties": {
+ "Email": {
+ "description": "Email address",
+ "type": "string",
+ "example": "john@example.com"
+ },
+ "Name": {
+ "description": "Optional name",
+ "type": "string",
+ "example": "John Doe"
+ }
+ }
+ },
+ "HTML": {
+ "description": "Message body (HTML)",
+ "type": "string",
+ "example": "\u003cdiv style=\"text-align:center\"\u003e\u003cp style=\"font-family: arial; font-size: 24px;\"\u003eMailpit is \u003cb\u003eawesome\u003c/b\u003e!\u003c/p\u003e\u003cp\u003e\u003cimg src=\"cid:mailpit-logo\" /\u003e\u003c/p\u003e\u003c/div\u003e"
+ },
+ "Headers": {
+ "description": "Optional headers in {\"key\":\"value\"} format",
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ },
+ "example": {
+ "X-IP": "1.2.3.4"
+ }
+ },
+ "ReplyTo": {
+ "description": "Optional Reply-To recipients",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": [
+ "Email"
+ ],
+ "properties": {
+ "Email": {
+ "description": "Email address",
+ "type": "string",
+ "example": "secretary@example.com"
+ },
+ "Name": {
+ "description": "Optional name",
+ "type": "string",
+ "example": "Secretary"
+ }
+ }
+ }
+ },
+ "Subject": {
+ "description": "Subject",
+ "type": "string",
+ "example": "Mailpit message via the HTTP API"
+ },
+ "Tags": {
+ "description": "Mailpit tags",
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "example": [
+ "Tag 1",
+ "Tag 2"
+ ]
+ },
+ "Text": {
+ "description": "Message body (text)",
+ "type": "string",
+ "example": "Mailpit is awesome!"
+ },
+ "To": {
+ "description": "\"To\" recipients",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": [
+ "Email"
+ ],
+ "properties": {
+ "Email": {
+ "description": "Email address",
+ "type": "string",
+ "example": "jane@example.com"
+ },
+ "Name": {
+ "description": "Optional name",
+ "type": "string",
+ "example": "Jane Doe"
+ }
+ }
+ }
+ }
+ }
}
}
],
"responses": {
"200": {
- "$ref": "#/responses/sendMessageResponse"
+ "$ref": "#/responses/SendMessageResponse"
},
"400": {
- "$ref": "#/responses/jsonErrorResponse"
+ "$ref": "#/responses/JSONErrorResponse"
}
}
}
@@ -984,7 +1153,7 @@
"application"
],
"summary": "Get web UI configuration",
- "operationId": "WebUIConfiguration",
+ "operationId": "WebUIConfigurationResponse",
"responses": {
"200": {
"$ref": "#/responses/WebUIConfigurationResponse"
@@ -1203,9 +1372,46 @@
},
"x-go-package": "github.com/axllent/mailpit/internal/storage"
},
+ "ChaosTrigger": {
+ "description": "Trigger for Chaos",
+ "type": "object",
+ "required": [
+ "ErrorCode",
+ "Probability"
+ ],
+ "properties": {
+ "ErrorCode": {
+ "description": "SMTP error code to return. The value must range from 400 to 599.",
+ "type": "integer",
+ "format": "int64",
+ "example": 451
+ },
+ "Probability": {
+ "description": "Probability (chance) of triggering the error. The value must range from 0 to 100.",
+ "type": "integer",
+ "format": "int64",
+ "example": 5
+ }
+ },
+ "x-go-name": "Trigger",
+ "x-go-package": "github.com/axllent/mailpit/internal/smtpd/chaos"
+ },
"ChaosTriggers": {
- "description": "ChaosTriggers are the Chaos triggers",
- "$ref": "#/definitions/Triggers"
+ "description": "Triggers for the Chaos configuration",
+ "type": "object",
+ "properties": {
+ "Authentication": {
+ "$ref": "#/definitions/ChaosTrigger"
+ },
+ "Recipient": {
+ "$ref": "#/definitions/ChaosTrigger"
+ },
+ "Sender": {
+ "$ref": "#/definitions/ChaosTrigger"
+ }
+ },
+ "x-go-name": "Triggers",
+ "x-go-package": "github.com/axllent/mailpit/internal/smtpd/chaos"
},
"HTMLCheckResponse": {
"description": "Response represents the HTML check response struct",
@@ -1384,18 +1590,6 @@
"x-go-name": "Warning",
"x-go-package": "github.com/axllent/mailpit/internal/htmlcheck"
},
- "JSONErrorMessage": {
- "description": "JSONErrorMessage struct",
- "type": "object",
- "properties": {
- "Error": {
- "description": "Error message",
- "type": "string",
- "example": "invalid format"
- }
- },
- "x-go-package": "github.com/axllent/mailpit/server/apiv1"
- },
"Link": {
"description": "Link struct",
"type": "object",
@@ -1571,7 +1765,7 @@
"type": "string"
}
},
- "x-go-name": "messageHeaders",
+ "x-go-name": "messageHeadersResponse",
"x-go-package": "github.com/axllent/mailpit/server/apiv1"
},
"MessageSummary": {
@@ -1731,192 +1925,6 @@
},
"x-go-package": "github.com/axllent/mailpit/internal/spamassassin"
},
- "SendMessageConfirmation": {
- "description": "SendMessageConfirmation struct",
- "type": "object",
- "properties": {
- "ID": {
- "description": "Database ID",
- "type": "string",
- "example": "iAfZVVe2UQfNSG5BAjgYwa"
- }
- },
- "x-go-package": "github.com/axllent/mailpit/server/apiv1"
- },
- "SendRequest": {
- "description": "SendRequest to send a message via HTTP",
- "type": "object",
- "required": [
- "From"
- ],
- "properties": {
- "Attachments": {
- "description": "Attachments",
- "type": "array",
- "items": {
- "type": "object",
- "required": [
- "Content",
- "Filename"
- ],
- "properties": {
- "Content": {
- "description": "Base64-encoded string of the file content",
- "type": "string",
- "example": "iVBORw0KGgoAAAANSUhEUgAAAEEAAAA8CAMAAAAOlSdoAAAACXBIWXMAAAHrAAAB6wGM2bZBAAAAS1BMVEVHcEwRfnUkZ2gAt4UsSF8At4UtSV4At4YsSV4At4YsSV8At4YsSV4At4YsSV4sSV4At4YsSV4At4YtSV4At4YsSV4At4YtSV8At4YsUWYNAAAAGHRSTlMAAwoXGiktRE5dbnd7kpOlr7zJ0d3h8PD8PCSRAAACWUlEQVR42pXT4ZaqIBSG4W9rhqQYocG+/ys9Y0Z0Br+x3j8zaxUPewFh65K+7yrIMeIY4MT3wPfEJCidKXEMnLaVkxDiELiMz4WEOAZSFghxBIypCOlKiAMgXfIqTnBgSm8CIQ6BImxEUxEckClVQiHGj4Ba4AQHikAIClwTE9KtIghAhUJwoLkmLnCiAHJLRKgIMsEtVUKbBUIwoAg2C4QgQBE6l4VCnApBgSKYLLApCnCa0+96AEMW2BQcmC+Pr3nfp7o5Exy49gIADcIqUELGfeA+bp93LmAJp8QJoEcN3C7NY3sbVANixMyI0nku20/n5/ZRf3KI2k6JEDWQtxcbdGuAqu3TAXG+/799Oyyas1B1MnMiA+XyxHp9q0PUKGPiRAau1fZbLRZV09wZcT8/gHk8QQAxXn8VgaDqcUmU6O/r28nbVwXAqca2mRNtPAF5+zoP2MeN9Fy4NgC6RfcbgE7XITBRYTtOE3U3C2DVff7pk+PkUxgAbvtnPXJaD6DxulMLwOhPS/M3MQkgg1ZFrIXnmfaZoOfpKiFgzeZD/WuKqQEGrfJYkyWf6vlG3xUgTuscnkNkQsb599q124kdpMUjCa/XARHs1gZymVtGt3wLkiFv8rUgTxitYCex5EVGec0Y9VmoDTFBSQte2TfXGXlf7hbdaUM9Sk7fisEN9qfBBTK+FZcvM9fQSdkl2vj4W2oX/bRogO3XasiNH7R0eW7fgRM834ImTg+Lg6BEnx4vz81rhr+MYPBBQg1v8GndEOrthxaCTxNAOut8WKLGZQl+MPz88Q9tAO/hVuSeqQAAAABJRU5ErkJggg=="
- },
- "ContentID": {
- "description": "Optional Content-ID (`cid`) for attachment.\nIf this field is set then the file is attached inline.",
- "type": "string",
- "example": "mailpit-logo"
- },
- "ContentType": {
- "description": "Optional Content Type for the the attachment.\nIf this field is not set (or empty) then the content type is automatically detected.",
- "type": "string",
- "example": "image/png"
- },
- "Filename": {
- "description": "Filename",
- "type": "string",
- "example": "mailpit.png"
- }
- }
- }
- },
- "Bcc": {
- "description": "Bcc recipients email addresses only",
- "type": "array",
- "items": {
- "type": "string"
- },
- "example": [
- "jack@example.com"
- ]
- },
- "Cc": {
- "description": "Cc recipients",
- "type": "array",
- "items": {
- "type": "object",
- "required": [
- "Email"
- ],
- "properties": {
- "Email": {
- "description": "Email address",
- "type": "string",
- "example": "manager@example.com"
- },
- "Name": {
- "description": "Optional name",
- "type": "string",
- "example": "Manager"
- }
- }
- }
- },
- "From": {
- "description": "\"From\" recipient",
- "type": "object",
- "required": [
- "Email"
- ],
- "properties": {
- "Email": {
- "description": "Email address",
- "type": "string",
- "example": "john@example.com"
- },
- "Name": {
- "description": "Optional name",
- "type": "string",
- "example": "John Doe"
- }
- }
- },
- "HTML": {
- "description": "Message body (HTML)",
- "type": "string",
- "example": "\u003cdiv style=\"text-align:center\"\u003e\u003cp style=\"font-family: arial; font-size: 24px;\"\u003eMailpit is \u003cb\u003eawesome\u003c/b\u003e!\u003c/p\u003e\u003cp\u003e\u003cimg src=\"cid:mailpit-logo\" /\u003e\u003c/p\u003e\u003c/div\u003e"
- },
- "Headers": {
- "description": "Optional headers in {\"key\":\"value\"} format",
- "type": "object",
- "additionalProperties": {
- "type": "string"
- },
- "example": {
- "X-IP": "1.2.3.4"
- }
- },
- "ReplyTo": {
- "description": "Optional Reply-To recipients",
- "type": "array",
- "items": {
- "type": "object",
- "required": [
- "Email"
- ],
- "properties": {
- "Email": {
- "description": "Email address",
- "type": "string",
- "example": "secretary@example.com"
- },
- "Name": {
- "description": "Optional name",
- "type": "string",
- "example": "Secretary"
- }
- }
- }
- },
- "Subject": {
- "description": "Subject",
- "type": "string",
- "example": "Mailpit message via the HTTP API"
- },
- "Tags": {
- "description": "Mailpit tags",
- "type": "array",
- "items": {
- "type": "string"
- },
- "example": [
- "Tag 1",
- "Tag 2"
- ]
- },
- "Text": {
- "description": "Message body (text)",
- "type": "string",
- "example": "Mailpit is awesome!"
- },
- "To": {
- "description": "\"To\" recipients",
- "type": "array",
- "items": {
- "type": "object",
- "required": [
- "Email"
- ],
- "properties": {
- "Email": {
- "description": "Email address",
- "type": "string",
- "example": "jane@example.com"
- },
- "Name": {
- "description": "Optional name",
- "type": "string",
- "example": "Jane Doe"
- }
- }
- }
- }
- },
- "x-go-package": "github.com/axllent/mailpit/server/apiv1"
- },
"SpamAssassinResponse": {
"description": "Result is a SpamAssassin result",
"type": "object",
@@ -1944,107 +1952,6 @@
},
"x-go-name": "Result",
"x-go-package": "github.com/axllent/mailpit/internal/spamassassin"
- },
- "Trigger": {
- "description": "Trigger for Chaos",
- "type": "object",
- "required": [
- "ErrorCode",
- "Probability"
- ],
- "properties": {
- "ErrorCode": {
- "description": "SMTP error code to return. The value must range from 400 to 599.",
- "type": "integer",
- "format": "int64",
- "example": 451
- },
- "Probability": {
- "description": "Probability (chance) of triggering the error. The value must range from 0 to 100.",
- "type": "integer",
- "format": "int64",
- "example": 5
- }
- },
- "x-go-package": "github.com/axllent/mailpit/internal/smtpd/chaos"
- },
- "Triggers": {
- "description": "Triggers for the Chaos configuration",
- "type": "object",
- "properties": {
- "Authentication": {
- "$ref": "#/definitions/Trigger"
- },
- "Recipient": {
- "$ref": "#/definitions/Trigger"
- },
- "Sender": {
- "$ref": "#/definitions/Trigger"
- }
- },
- "x-go-package": "github.com/axllent/mailpit/internal/smtpd/chaos"
- },
- "WebUIConfiguration": {
- "description": "Response includes global web UI settings",
- "type": "object",
- "properties": {
- "ChaosEnabled": {
- "description": "Whether Chaos support is enabled at runtime",
- "type": "boolean"
- },
- "DuplicatesIgnored": {
- "description": "Whether messages with duplicate IDs are ignored",
- "type": "boolean"
- },
- "HideDeleteAllButton": {
- "description": "Whether the delete button should be hidden",
- "type": "boolean"
- },
- "Label": {
- "description": "Optional label to identify this Mailpit instance",
- "type": "string"
- },
- "MessageRelay": {
- "description": "Message Relay information",
- "type": "object",
- "properties": {
- "AllowedRecipients": {
- "description": "Only allow relaying to these recipients (regex)",
- "type": "string"
- },
- "BlockedRecipients": {
- "description": "Block relaying to these recipients (regex)",
- "type": "string"
- },
- "Enabled": {
- "description": "Whether message relaying (release) is enabled",
- "type": "boolean"
- },
- "OverrideFrom": {
- "description": "Overrides the \"From\" address for all relayed messages",
- "type": "string"
- },
- "PreserveMessageIDs": {
- "description": "Preserve the original Message-IDs when relaying messages",
- "type": "boolean"
- },
- "ReturnPath": {
- "description": "Enforced Return-Path (if set) for relay bounces",
- "type": "string"
- },
- "SMTPServer": {
- "description": "The configured SMTP server address",
- "type": "string"
- }
- }
- },
- "SpamAssassin": {
- "description": "Whether SpamAssassin is enabled",
- "type": "boolean"
- }
- },
- "x-go-name": "webUIConfiguration",
- "x-go-package": "github.com/axllent/mailpit/server/apiv1"
}
},
"responses": {
@@ -2087,6 +1994,19 @@
"type": "string"
}
},
+ "JSONErrorResponse": {
+ "description": "JSON error response",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "Error": {
+ "description": "Error message",
+ "type": "string",
+ "example": "invalid format"
+ }
+ }
+ }
+ },
"MessagesSummaryResponse": {
"description": "Summary of messages",
"schema": {
@@ -2105,6 +2025,19 @@
"type": "string"
}
},
+ "SendMessageResponse": {
+ "description": "Confirmation message for HTTP send API",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "ID": {
+ "description": "Database ID",
+ "type": "string",
+ "example": "iAfZVVe2UQfNSG5BAjgYwa"
+ }
+ }
+ }
+ },
"TextResponse": {
"description": "Plain text response",
"schema": {
@@ -2114,19 +2047,63 @@
"WebUIConfigurationResponse": {
"description": "Web UI configuration response",
"schema": {
- "$ref": "#/definitions/WebUIConfiguration"
- }
- },
- "jsonErrorResponse": {
- "description": "JSON error response",
- "schema": {
- "$ref": "#/definitions/JSONErrorMessage"
- }
- },
- "sendMessageResponse": {
- "description": "Confirmation message for HTTP send API",
- "schema": {
- "$ref": "#/definitions/SendMessageConfirmation"
+ "type": "object",
+ "properties": {
+ "ChaosEnabled": {
+ "description": "Whether Chaos support is enabled at runtime",
+ "type": "boolean"
+ },
+ "DuplicatesIgnored": {
+ "description": "Whether messages with duplicate IDs are ignored",
+ "type": "boolean"
+ },
+ "HideDeleteAllButton": {
+ "description": "Whether the delete button should be hidden",
+ "type": "boolean"
+ },
+ "Label": {
+ "description": "Optional label to identify this Mailpit instance",
+ "type": "string"
+ },
+ "MessageRelay": {
+ "description": "Message Relay information",
+ "type": "object",
+ "properties": {
+ "AllowedRecipients": {
+ "description": "Only allow relaying to these recipients (regex)",
+ "type": "string"
+ },
+ "BlockedRecipients": {
+ "description": "Block relaying to these recipients (regex)",
+ "type": "string"
+ },
+ "Enabled": {
+ "description": "Whether message relaying (release) is enabled",
+ "type": "boolean"
+ },
+ "OverrideFrom": {
+ "description": "Overrides the \"From\" address for all relayed messages",
+ "type": "string"
+ },
+ "PreserveMessageIDs": {
+ "description": "Preserve the original Message-IDs when relaying messages",
+ "type": "boolean"
+ },
+ "ReturnPath": {
+ "description": "Enforced Return-Path (if set) for relay bounces",
+ "type": "string"
+ },
+ "SMTPServer": {
+ "description": "The configured SMTP server address",
+ "type": "string"
+ }
+ }
+ },
+ "SpamAssassin": {
+ "description": "Whether SpamAssassin is enabled",
+ "type": "boolean"
+ }
+ }
}
}
}