diff --git a/server/apiv1/api.go b/server/apiv1/api.go index d5fd63d..59d564e 100644 --- a/server/apiv1/api.go +++ b/server/apiv1/api.go @@ -14,6 +14,7 @@ import ( "github.com/axllent/mailpit/server/smtpd" "github.com/axllent/mailpit/storage" "github.com/axllent/mailpit/utils/htmlcheck" + "github.com/axllent/mailpit/utils/linkcheck" "github.com/axllent/mailpit/utils/logger" "github.com/axllent/mailpit/utils/tools" "github.com/gorilla/mux" @@ -638,7 +639,7 @@ func HTMLCheck(w http.ResponseWriter, r *http.Request) { // // # HTML check (beta) // - // Returns the summary of HTML check. + // Returns the summary of the message HTML checker. // // NOTE: This feature is currently in beta and is documented for reference only. // Please do not integrate with it (yet) as there may be changes. @@ -684,6 +685,62 @@ func HTMLCheck(w http.ResponseWriter, r *http.Request) { _, _ = w.Write(bytes) } +// 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 LinkCheckResponse + // + // # Link check (beta) + // + // Returns the summary of the message Link checker. + // + // NOTE: This feature is currently in beta and is documented for reference only. + // Please do not integrate with it (yet) as there may be changes. + // + // Produces: + // - application/json + // + // Schemes: http, https + // + // Parameters: + // + name: ID + // in: path + // description: Database ID + // required: true + // type: string + // + name: follow + // in: query + // description: Follow redirects + // required: false + // type: boolean + // default: false + // + // Responses: + // 200: LinkCheckResponse + // default: ErrorResponse + + vars := mux.Vars(r) + id := vars["id"] + + msg, err := storage.GetMessage(id) + if err != nil { + fourOFour(w) + return + } + + f := r.URL.Query().Get("follow") + followRedirects := f == "true" || f == "1" + + summary, err := linkcheck.RunTests(msg, followRedirects) + if err != nil { + httpError(w, err.Error()) + return + } + + bytes, _ := json.Marshal(summary) + w.Header().Add("Content-Type", "application/json") + _, _ = w.Write(bytes) +} + // FourOFour returns a basic 404 message func fourOFour(w http.ResponseWriter) { w.Header().Set("Referrer-Policy", "no-referrer") diff --git a/server/apiv1/structs.go b/server/apiv1/structs.go index 95f0bd3..7bdb5a0 100644 --- a/server/apiv1/structs.go +++ b/server/apiv1/structs.go @@ -3,6 +3,7 @@ package apiv1 import ( "github.com/axllent/mailpit/storage" "github.com/axllent/mailpit/utils/htmlcheck" + "github.com/axllent/mailpit/utils/linkcheck" ) // MessagesSummary is a summary of a list of messages @@ -49,3 +50,6 @@ type Attachment = storage.Attachment // HTMLCheckResponse summary type HTMLCheckResponse = htmlcheck.Response + +// LinkCheckResponse summary +type LinkCheckResponse = linkcheck.Response diff --git a/server/server.go b/server/server.go index b90c06f..b1c6946 100644 --- a/server/server.go +++ b/server/server.go @@ -95,6 +95,7 @@ func defaultRoutes() *mux.Router { if !config.DisableHTMLCheck { r.HandleFunc(config.Webroot+"api/v1/message/{id}/html-check", middleWareFunc(apiv1.HTMLCheck)).Methods("GET") } + r.HandleFunc(config.Webroot+"api/v1/message/{id}/link-check", middleWareFunc(apiv1.LinkCheck)).Methods("GET") r.HandleFunc(config.Webroot+"api/v1/message/{id}", middleWareFunc(apiv1.GetMessage)).Methods("GET") r.HandleFunc(config.Webroot+"api/v1/info", middleWareFunc(apiv1.AppInfo)).Methods("GET") r.HandleFunc(config.Webroot+"api/v1/webui", middleWareFunc(apiv1.WebUIConfig)).Methods("GET") diff --git a/server/ui-src/assets/styles.scss b/server/ui-src/assets/styles.scss index 7695651..0cf6341 100644 --- a/server/ui-src/assets/styles.scss +++ b/server/ui-src/assets/styles.scss @@ -39,14 +39,13 @@ } .nav-tabs .nav-link { - @include media-breakpoint-down(sm) { - // font-size: 14px; + @include media-breakpoint-down(xl) { padding-left: 10px; padding-right: 10px; } } -:not(.text-view) > a { +:not(.text-view) > a:not(.no-icon) { &[href^="http://"], &[href^="https://"] { diff --git a/server/ui-src/templates/Message.vue b/server/ui-src/templates/Message.vue index 5795c62..224a5cf 100644 --- a/server/ui-src/templates/Message.vue +++ b/server/ui-src/templates/Message.vue @@ -6,6 +6,7 @@ import Tags from "bootstrap5-tags" import Attachments from './Attachments.vue' import Headers from './Headers.vue' import HTMLCheck from './MessageHTMLCheck.vue' +import LinkCheck from './MessageLinkCheck.vue' export default { props: { @@ -18,6 +19,7 @@ export default { Attachments, Headers, HTMLCheck, + LinkCheck, }, mixins: [commonMixins], @@ -33,6 +35,7 @@ export default { loadHeaders: false, htmlScore: false, htmlScoreColor: false, + linkCheckErrors: false, showMobileButtons: false, scaleHTMLPreview: 'display', // keys names match bootstrap icon names @@ -219,7 +222,7 @@ export default { let html = s // full links with http(s) - let re = /(\b(https?|ftp):\/\/[\-\w@:%_\+.~#?,&\/\/=;]+)\b/gim + let re = /(\b(https?|ftp):\/\/[\-\w@:%_\+'!.~#?,&\/\/=;]+)/gim html = html.replace(re, '˱˱˱a href=ˠˠˠ$&ˠˠˠ target=_blank rel=noopener˲˲˲$&˱˱˱/a˲˲˲') // plain www links without https?:// prefix @@ -366,15 +369,51 @@ export default { role="tab" aria-controls="nav-raw" aria-selected="false"> Raw - + + + +
diff --git a/server/ui-src/templates/MessageHTMLCheck.vue b/server/ui-src/templates/MessageHTMLCheck.vue index 32ab463..376f67c 100644 --- a/server/ui-src/templates/MessageHTMLCheck.vue +++ b/server/ui-src/templates/MessageHTMLCheck.vue @@ -640,7 +640,7 @@ export default {