From f16b105d2607c5435481275a8d9bf84c77db1466 Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Fri, 31 Mar 2023 23:34:59 +1300 Subject: [PATCH 1/3] API: Include Reply-To in message summary (including Web UI) This adds a new ReplyTo array to to API Message response, and displays in the web UI if set. See #66 --- docs/apiv1/Message.md | 3 ++- server/ui-src/templates/Message.vue | 26 ++++++++++++++++++-------- server/ui/api/v1/swagger.json | 7 +++++++ storage/database.go | 1 + storage/structs.go | 2 ++ 5 files changed, 30 insertions(+), 9 deletions(-) diff --git a/docs/apiv1/Message.md b/docs/apiv1/Message.md index 5cf47b5..d40c36e 100644 --- a/docs/apiv1/Message.md +++ b/docs/apiv1/Message.md @@ -28,6 +28,7 @@ Returns a JSON summary of the message and attachments. ], "Cc": [], "Bcc": [], + "ReplyTo": [], "Subject": "Message subject", "Date": "2016-09-07T16:46:00+13:00", "Text": "Plain text MIME part of the email", @@ -57,7 +58,7 @@ Returns a JSON summary of the message and attachments. - `Read` - always true (message marked read on open) - `From` - Name & Address, or null -- `To`, `CC`, `BCC` - Array of Names & Address +- `To`, `CC`, `BCC`, `ReplyTo` - Array of Names & Address - `Date` - Parsed email local date & time from headers - `Size` - Total size of raw email - `Inline`, `Attachments` - Array of attachments and inline images. diff --git a/server/ui-src/templates/Message.vue b/server/ui-src/templates/Message.vue index 8bcc22f..880cc60 100644 --- a/server/ui-src/templates/Message.vue +++ b/server/ui-src/templates/Message.vue @@ -147,12 +147,14 @@ export default {
- - + + @@ -174,7 +176,7 @@ export default { @@ -182,7 +184,15 @@ export default { + + + + diff --git a/server/ui/api/v1/swagger.json b/server/ui/api/v1/swagger.json index def408a..d67e95b 100644 --- a/server/ui/api/v1/swagger.json +++ b/server/ui/api/v1/swagger.json @@ -586,6 +586,13 @@ "description": "Read status", "type": "boolean" }, + "ReplyTo": { + "description": "ReplyTo addresses", + "type": "array", + "items": { + "$ref": "#/definitions/Address" + } + }, "Size": { "description": "Message size in bytes", "type": "integer", diff --git a/storage/database.go b/storage/database.go index 21e71fb..d08899a 100644 --- a/storage/database.go +++ b/storage/database.go @@ -442,6 +442,7 @@ func GetMessage(id string) (*Message, error) { To: addressToSlice(env, "To"), Cc: addressToSlice(env, "Cc"), Bcc: addressToSlice(env, "Bcc"), + ReplyTo: addressToSlice(env, "Reply-To"), Subject: env.GetHeader("Subject"), Tags: getMessageTags(id), Size: len(raw), diff --git a/storage/structs.go b/storage/structs.go index 733614a..7d61f78 100644 --- a/storage/structs.go +++ b/storage/structs.go @@ -23,6 +23,8 @@ type Message struct { Cc []*mail.Address // Bcc addresses Bcc []*mail.Address + // ReplyTo addresses + ReplyTo []*mail.Address // Message subject Subject string // Message date if set, else date received From 1b798c5514fb386cfb874baad05124389c31c9ee Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Sat, 1 Apr 2023 17:02:49 +1300 Subject: [PATCH 2/3] UI: Tab to view formatted message headers See #71 --- README.md | 7 +++++- server/ui-src/assets/styles.scss | 8 ++++++ server/ui-src/templates/Headers.vue | 38 +++++++++++++++++++++++++++++ server/ui-src/templates/Message.vue | 30 +++++++++++++++++++---- 4 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 server/ui-src/templates/Headers.vue diff --git a/README.md b/README.md index 2a70794..1f93c51 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Mailpit is inspired by [MailHog](#why-rewrite-mailhog), but much, much faster. - Runs entirely from a single binary, no installation required - SMTP server (default `0.0.0.0:1025`) -- Web UI to view emails (formatted HTML, highlighted HTML source, text, raw source and MIME attachments including image thumbnails) +- Web UI to view emails (formatted HTML, highlighted HTML source, text, headers, raw source and MIME attachments including image thumbnails) - Advanced mail search ([see wiki](https://github.com/axllent/mailpit/wiki/Mail-search)) - Message tagging ([see wiki](https://github.com/axllent/mailpit/wiki/Tagging)) - Real-time web UI updates using web sockets for new mail @@ -41,10 +41,12 @@ The Mailpit web UI listens by default on `http://0.0.0.0:8025`, and the SMTP por Mailpit runs as a single binary and can be installed in different ways: + ### Install via Brew (Mac) Add the repository to your taps with `brew tap axllent/apps`, and then install Mailpit with `brew install mailpit`. + ### Install via bash script (Linux & Mac) Linux & Mac users can install it directly to `/usr/local/bin/mailpit` with: @@ -53,14 +55,17 @@ Linux & Mac users can install it directly to `/usr/local/bin/mailpit` with: sudo bash < <(curl -sL https://raw.githubusercontent.com/axllent/mailpit/develop/install.sh) ``` + ### Download static binary (Windows, Linux and Mac) Static binaries can always be found on the [releases](https://github.com/axllent/mailpit/releases/latest). The `mailpit` binary can extracted and copied to your `$PATH`, or simply run as `./mailpit`. + ### Docker See [Docker instructions](https://github.com/axllent/mailpit/wiki/Docker-images). + ### Compile from source To build Mailpit from source see [building from source](https://github.com/axllent/mailpit/wiki/Building-from-source). diff --git a/server/ui-src/assets/styles.scss b/server/ui-src/assets/styles.scss index db717b4..26d628e 100644 --- a/server/ui-src/assets/styles.scss +++ b/server/ui-src/assets/styles.scss @@ -38,6 +38,14 @@ } } +.nav-tabs .nav-link { + @include media-breakpoint-down(sm) { + // font-size: 14px; + padding-left: 10px; + padding-right: 10px; + } +} + #loading { position: absolute; top: 0; diff --git a/server/ui-src/templates/Headers.vue b/server/ui-src/templates/Headers.vue new file mode 100644 index 0000000..a12357c --- /dev/null +++ b/server/ui-src/templates/Headers.vue @@ -0,0 +1,38 @@ + + + + diff --git a/server/ui-src/templates/Message.vue b/server/ui-src/templates/Message.vue index 880cc60..b8f47e4 100644 --- a/server/ui-src/templates/Message.vue +++ b/server/ui-src/templates/Message.vue @@ -4,6 +4,7 @@ import commonMixins from '../mixins.js'; import Prism from "prismjs"; import Tags from "bootstrap5-tags"; import Attachments from './Attachments.vue'; +import Headers from './Headers.vue'; export default { props: { @@ -12,7 +13,8 @@ export default { }, components: { - Attachments + Attachments, + Headers }, mixins: [commonMixins], @@ -24,6 +26,7 @@ export default { showTags: false, // to force rerendering of component messageTags: [], allTags: [], + loadHeaders: false } }, @@ -34,6 +37,7 @@ export default { self.showTags = false; self.messageTags = self.message.Tags; self.allTags = self.existingTags; + self.loadHeaders = false; // delay to select first tab and add HTML highlighting (prev/next) self.$nextTick(function () { self.renderUI(); @@ -60,9 +64,16 @@ export default { self.allTags = self.existingTags; window.addEventListener("resize", self.resizeIframes); self.renderUI(); - var tabEl = document.getElementById('nav-raw-tab'); - tabEl.addEventListener('shown.bs.tab', function (event) { + + let headersTab = document.getElementById('nav-headers-tab'); + headersTab.addEventListener('shown.bs.tab', function (event) { + self.loadHeaders = true; + }); + + let rawTab = document.getElementById('nav-raw-tab'); + rawTab.addEventListener('shown.bs.tab', function (event) { self.srcURI = 'api/v1/message/' + self.message.ID + '/raw'; + self.resizeIframes(); }); self.showTags = true; @@ -236,15 +247,21 @@ export default { + type="button" role="tab" aria-controls="nav-html-source" aria-selected="false" v-if="message.HTML"> + HTML SrcSource + + +
From
From {{ message.From.Name + " " }} - <{{ message.From.Address }}> + + <{{ message.From.Address }}> + [ Unknown ] @@ -164,9 +166,9 @@ export default { - {{ t.Name + " <" + t.Address + ">" }} - - Undisclosed recipients + {{ t.Name + " <" + t.Address + ">" }} + + Undisclosed recipients
- {{ t.Name + " <" + t.Address + ">" }} + {{ t.Name + " <" + t.Address + ">" }}
- {{ t.Name + " <" + t.Address + ">" }} + {{ t.Name + " <" + t.Address + ">" }} +
Reply-To + + + {{ t.Name + " <" + t.Address + ">" }}