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

Chore: Refactor API Swagger definitions and remove unused structs

- Removed deprecated `thumbnailParams` struct from `thumbnails.go`.
- Updated `server_test.go` to use an anonymous struct for response unmarshalling.
- Enhanced `swagger.json` with detailed definitions for SendRequest and SendMessageResponse.
- Introduced new `swaggerParams.go` to define Swagger parameters for various API endpoints.
- Created `swaggerResponses.go` to define Swagger responses for API endpoints.
- Cleaned up unused JSON error message definitions and consolidated error responses.
- Improved documentation for Chaos triggers and web UI configuration responses.
This commit is contained in:
Ralph Slooten
2025-06-22 15:03:55 +12:00
parent f99d9ecf69
commit e29883fa1c
18 changed files with 906 additions and 934 deletions

View File

@@ -26,6 +26,7 @@
"Mechs",
"navhtml",
"neostandard",
"nolint",
"popperjs",
"readyz",
"RSET",

View File

@@ -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

View File

@@ -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 {

View File

@@ -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())
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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: <div style="text-align:center"><p style="font-family: arial; font-size: 24px;">Mailpit is <b>awesome</b>!</p><p><img src="cid:mailpit-logo" /></p></div>
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,<base64String>
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)
}

View File

@@ -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
}

View File

@@ -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: <div style="text-align:center"><p style="font-family: arial; font-size: 24px;">Mailpit is <b>awesome</b>!</p><p><img src="cid:mailpit-logo" /></p></div>
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
}

View File

@@ -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
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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())

View File

@@ -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,48 +1952,101 @@
},
"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"
"responses": {
"AppInfoResponse": {
"description": "Application information",
"schema": {
"$ref": "#/definitions/AppInformation"
}
},
"x-go-package": "github.com/axllent/mailpit/internal/smtpd/chaos"
"ArrayResponse": {
"description": "Plain JSON array response",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
},
"WebUIConfiguration": {
"description": "Response includes global web UI settings",
"BinaryResponse": {
"description": "Binary data response which inherits the attachment's content type.",
"schema": {
"type": "string"
}
},
"ChaosResponse": {
"description": "Response for the Chaos triggers configuration",
"schema": {
"$ref": "#/definitions/ChaosTriggers"
}
},
"ErrorResponse": {
"description": "Server error will return with a 400 status code\nwith the error message in the body",
"schema": {
"type": "string"
}
},
"HTMLResponse": {
"description": "HTML response",
"schema": {
"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": {
"$ref": "#/definitions/MessagesSummary"
}
},
"NotFoundResponse": {
"description": "Not found error will return a 404 status code",
"schema": {
"type": "string"
}
},
"OKResponse": {
"description": "Plain text \"ok\" response",
"schema": {
"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": {
"type": "string"
}
},
"WebUIConfigurationResponse": {
"description": "Web UI configuration response",
"schema": {
"type": "object",
"properties": {
"ChaosEnabled": {
@@ -2042,91 +2103,7 @@
"description": "Whether SpamAssassin is enabled",
"type": "boolean"
}
},
"x-go-name": "webUIConfiguration",
"x-go-package": "github.com/axllent/mailpit/server/apiv1"
}
},
"responses": {
"AppInfoResponse": {
"description": "Application information",
"schema": {
"$ref": "#/definitions/AppInformation"
}
},
"ArrayResponse": {
"description": "Plain JSON array response",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
},
"BinaryResponse": {
"description": "Binary data response which inherits the attachment's content type.",
"schema": {
"type": "string"
}
},
"ChaosResponse": {
"description": "Response for the Chaos triggers configuration",
"schema": {
"$ref": "#/definitions/ChaosTriggers"
}
},
"ErrorResponse": {
"description": "Server error will return with a 400 status code\nwith the error message in the body",
"schema": {
"type": "string"
}
},
"HTMLResponse": {
"description": "HTML response",
"schema": {
"type": "string"
}
},
"MessagesSummaryResponse": {
"description": "Summary of messages",
"schema": {
"$ref": "#/definitions/MessagesSummary"
}
},
"NotFoundResponse": {
"description": "Not found error will return a 404 status code",
"schema": {
"type": "string"
}
},
"OKResponse": {
"description": "Plain text \"ok\" response",
"schema": {
"type": "string"
}
},
"TextResponse": {
"description": "Plain text response",
"schema": {
"type": "string"
}
},
"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"
}
}
}