mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-18 10:07:02 +00:00
Merge branch 'feature/mime-errors' into develop
This commit is contained in:
31
etc/swaks-tests/mime-errors.raw
Normal file
31
etc/swaks-tests/mime-errors.raw
Normal file
@@ -0,0 +1,31 @@
|
||||
Date: %DATE%
|
||||
To: %TO_ADDRESS%
|
||||
From: %FROM_ADDRESS%
|
||||
Subject: MIME Errors
|
||||
Message-Id: <07B7061D-2676-487E-942E-C341CE4D13DC@makita.skynet>
|
||||
Content-Type: multipart/alternative; boundary="Enmime-Test-100"
|
||||
|
||||
--Enmime-Test-100
|
||||
Content-Transfer-Encoding: 8bit
|
||||
Content-Type: text/plain; charset=us-ascii
|
||||
|
||||
Using Unicode/UTF-8, you can write in emails and source code things such as
|
||||
|
||||
Mathematics and sciences:
|
||||
|
||||
∮ E⋅da = Q, n → ∞, ∑ f(i) = ∏ g(i), ⎧⎡⎛┌─────┐⎞⎤⎫
|
||||
⎪⎢⎜│a²+b³ ⎟⎥⎪
|
||||
∀x∈ℝ: ⌈x⌉ = −⌊−x⌋, α ∧ ¬β = ¬(¬α ∨ β), ⎪⎢⎜│───── ⎟⎥⎪
|
||||
⎪⎢⎜⎷ c₈ ⎟⎥⎪
|
||||
ℕ ⊆ ℕ₀ ⊂ ℤ ⊂ ℚ ⊂ ℝ ⊂ ℂ, ⎨⎢⎜ ⎟⎥⎬
|
||||
⎪⎢⎜ ∞ ⎟⎥⎪
|
||||
⊥ < a ≠ b ≡ c ≤ d ≪ ⊤ ⇒ (⟦A⟧ ⇔ ⟪B⟫), ⎪⎢⎜ ⎲ ⎟⎥⎪
|
||||
⎪⎢⎜ ⎳aⁱ-bⁱ⎟⎥⎪
|
||||
2H₂ + O₂ ⇌ 2H₂O, R = 4.7 kΩ, ⌀ 200 mm ⎩⎣⎝i=1 ⎠⎦⎭
|
||||
|
||||
Linguistics and dictionaries:
|
||||
|
||||
ði ıntəˈnæʃənəl fəˈnɛtık əsoʊsiˈeıʃn
|
||||
Y [ˈʏpsilɔn], Yen [jɛn], Yoga [ˈjoːgɑ]
|
||||
|
||||
--Enmime-Test-100
|
||||
@@ -56,3 +56,6 @@ swaks $* --data outlook.raw
|
||||
# Non-mime responsive HTML test
|
||||
swaks $* --data nonmime-html-responsive.raw
|
||||
swaks $* --data nonmime-html-inlined.raw
|
||||
|
||||
# Incorrect charset, malformed final boundary
|
||||
swaks $* --data mime-errors.raw
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/jhillyerd/inbucket/pkg/server/web"
|
||||
"github.com/jhillyerd/inbucket/pkg/storage"
|
||||
@@ -15,30 +14,6 @@ import (
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// JSONMessage formats message data for the UI.
|
||||
type JSONMessage struct {
|
||||
Mailbox string `json:"mailbox"`
|
||||
ID string `json:"id"`
|
||||
From string `json:"from"`
|
||||
To []string `json:"to"`
|
||||
Subject string `json:"subject"`
|
||||
Date time.Time `json:"date"`
|
||||
PosixMillis int64 `json:"posix-millis"`
|
||||
Size int64 `json:"size"`
|
||||
Seen bool `json:"seen"`
|
||||
Header map[string][]string `json:"header"`
|
||||
Text string `json:"text"`
|
||||
HTML string `json:"html"`
|
||||
Attachments []*JSONAttachment `json:"attachments"`
|
||||
}
|
||||
|
||||
// JSONAttachment formats attachment data for the UI.
|
||||
type JSONAttachment struct {
|
||||
ID string `json:"id"`
|
||||
FileName string `json:"filename"`
|
||||
ContentType string `json:"content-type"`
|
||||
}
|
||||
|
||||
// MailboxMessage outputs a particular message as JSON for the UI.
|
||||
func MailboxMessage(w http.ResponseWriter, req *http.Request, ctx *web.Context) (err error) {
|
||||
id := ctx.Vars["id"]
|
||||
@@ -54,15 +29,25 @@ func MailboxMessage(w http.ResponseWriter, req *http.Request, ctx *web.Context)
|
||||
http.NotFound(w, req)
|
||||
return nil
|
||||
}
|
||||
attachParts := msg.Attachments()
|
||||
attachments := make([]*JSONAttachment, len(attachParts))
|
||||
for i, part := range attachParts {
|
||||
attachments[i] = &JSONAttachment{
|
||||
|
||||
attachments := make([]*jsonAttachment, 0)
|
||||
for i, part := range msg.Attachments() {
|
||||
attachments = append(attachments, &jsonAttachment{
|
||||
ID: strconv.Itoa(i),
|
||||
FileName: part.FileName,
|
||||
ContentType: part.ContentType,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
mimeErrors := make([]*jsonMIMEError, 0)
|
||||
for _, e := range msg.MIMEErrors() {
|
||||
mimeErrors = append(mimeErrors, &jsonMIMEError{
|
||||
Name: e.Name,
|
||||
Detail: e.Detail,
|
||||
Severe: e.Severe,
|
||||
})
|
||||
}
|
||||
|
||||
// Sanitize HTML body.
|
||||
htmlBody := ""
|
||||
if msg.HTML() != "" {
|
||||
@@ -74,8 +59,9 @@ func MailboxMessage(w http.ResponseWriter, req *http.Request, ctx *web.Context)
|
||||
Msg("HTML sanitizer failed")
|
||||
}
|
||||
}
|
||||
|
||||
return web.RenderJSON(w,
|
||||
&JSONMessage{
|
||||
&jsonMessage{
|
||||
Mailbox: name,
|
||||
ID: msg.ID,
|
||||
From: msg.From.String(),
|
||||
@@ -89,6 +75,7 @@ func MailboxMessage(w http.ResponseWriter, req *http.Request, ctx *web.Context)
|
||||
Text: web.TextToHTML(msg.Text()),
|
||||
HTML: htmlBody,
|
||||
Attachments: attachments,
|
||||
Errors: mimeErrors,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
34
pkg/webui/mailbox_json.go
Normal file
34
pkg/webui/mailbox_json.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package webui
|
||||
|
||||
import "time"
|
||||
|
||||
// jsonMessage formats message data for the UI.
|
||||
type jsonMessage struct {
|
||||
Mailbox string `json:"mailbox"`
|
||||
ID string `json:"id"`
|
||||
From string `json:"from"`
|
||||
To []string `json:"to"`
|
||||
Subject string `json:"subject"`
|
||||
Date time.Time `json:"date"`
|
||||
PosixMillis int64 `json:"posix-millis"`
|
||||
Size int64 `json:"size"`
|
||||
Seen bool `json:"seen"`
|
||||
Header map[string][]string `json:"header"`
|
||||
Text string `json:"text"`
|
||||
HTML string `json:"html"`
|
||||
Attachments []*jsonAttachment `json:"attachments"`
|
||||
Errors []*jsonMIMEError `json:"errors"`
|
||||
}
|
||||
|
||||
// jsonAttachment formats attachment data for the UI.
|
||||
type jsonAttachment struct {
|
||||
ID string `json:"id"`
|
||||
FileName string `json:"filename"`
|
||||
ContentType string `json:"content-type"`
|
||||
}
|
||||
|
||||
type jsonMIMEError struct {
|
||||
Name string `json:"name"`
|
||||
Detail string `json:"detail"`
|
||||
Severe bool `json:"severe"`
|
||||
}
|
||||
@@ -18,6 +18,7 @@ type alias Message =
|
||||
, text : String
|
||||
, html : String
|
||||
, attachments : List Attachment
|
||||
, errors : List Error
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +29,13 @@ type alias Attachment =
|
||||
}
|
||||
|
||||
|
||||
type alias Error =
|
||||
{ name : String
|
||||
, detail : String
|
||||
, severe : Bool
|
||||
}
|
||||
|
||||
|
||||
decoder : Decoder Message
|
||||
decoder =
|
||||
succeed Message
|
||||
@@ -42,6 +50,7 @@ decoder =
|
||||
|> required "text" string
|
||||
|> required "html" string
|
||||
|> required "attachments" (list attachmentDecoder)
|
||||
|> required "errors" (list errorDecoder)
|
||||
|
||||
|
||||
attachmentDecoder : Decoder Attachment
|
||||
@@ -50,3 +59,11 @@ attachmentDecoder =
|
||||
|> required "id" string
|
||||
|> required "filename" string
|
||||
|> required "content-type" string
|
||||
|
||||
|
||||
errorDecoder : Decoder Error
|
||||
errorDecoder =
|
||||
succeed Error
|
||||
|> required "name" string
|
||||
|> required "detail" string
|
||||
|> required "severe" bool
|
||||
|
||||
@@ -590,11 +590,34 @@ viewMessage zone message bodyMode =
|
||||
, dt [] [ text "Subject:" ]
|
||||
, dd [] [ text message.subject ]
|
||||
]
|
||||
, messageErrors message
|
||||
, messageBody message bodyMode
|
||||
, attachments message
|
||||
]
|
||||
|
||||
|
||||
messageErrors : Message -> Html Msg
|
||||
messageErrors message =
|
||||
let
|
||||
row error =
|
||||
li []
|
||||
[ span
|
||||
[ classList [ ( "warn-severe", error.severe ) ] ]
|
||||
[ text (error.name ++ ": ") ]
|
||||
, text error.detail
|
||||
]
|
||||
in
|
||||
case message.errors of
|
||||
[] ->
|
||||
text ""
|
||||
|
||||
errors ->
|
||||
div [ class "warn" ]
|
||||
[ div [] [ h3 [] [ text "MIME problems detected" ] ]
|
||||
, ul [] (List.map row errors)
|
||||
]
|
||||
|
||||
|
||||
messageBody : Message -> Body -> Html Msg
|
||||
messageBody message bodyMode =
|
||||
let
|
||||
|
||||
@@ -141,6 +141,11 @@ h2 {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.error {
|
||||
background-color: #f58080;
|
||||
background-image: linear-gradient(to bottom, #e86060 0, #f58080 100%);
|
||||
@@ -203,6 +208,27 @@ h2 {
|
||||
padding: 10px !important;
|
||||
}
|
||||
|
||||
.warn {
|
||||
--light: #f5f580;
|
||||
--dark: #e8e860;
|
||||
background-color: var(--light);
|
||||
background-image: linear-gradient(to bottom, var(--dark) 0, var(--light) 100%);
|
||||
border: 1px solid var(--dark);
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,.05);
|
||||
padding: 6px 10px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.warn li {
|
||||
margin-left: 20px;
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
.warn-severe {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/** NAV BAR */
|
||||
|
||||
.navbar,
|
||||
|
||||
Reference in New Issue
Block a user