1
0
mirror of https://github.com/axllent/mailpit.git synced 2025-04-25 12:25:04 +02:00

Feature: Download raw message, HTML/text body parts or attachments via single button

@see #67
This commit is contained in:
Ralph Slooten 2023-03-29 17:23:47 +13:00
parent 2d07683a28
commit 3bb9f4162a
3 changed files with 70 additions and 28 deletions

View File

@ -542,6 +542,14 @@ export default {
self.appInfo = response.data; self.appInfo = response.data;
self.modal('AppInfoModal').show(); self.modal('AppInfoModal').show();
}); });
},
downloadMessageBody: function (str, ext) {
let dl = document.createElement('a');
dl.href = "data:text/plain," + encodeURIComponent(str);
dl.target = '_blank';
dl.download = this.message.ID + '.' + ext;
dl.click();
} }
} }
} }
@ -575,10 +583,49 @@ export default {
:href="'#' + messagePrev" title="View previous message"> :href="'#' + messagePrev" title="View previous message">
<i class="bi bi-caret-left-fill"></i> <i class="bi bi-caret-left-fill"></i>
</a> </a>
<a :href="'api/v1/message/' + message.ID + '/raw?dl=1'" class="btn btn-outline-light me-2 float-end" <div class="dropdown float-end" id="DownloadBtn">
title="Download message"> <button type="button" class="btn btn-outline-light dropdown-toggle" data-bs-toggle="dropdown"
<i class="bi bi-file-arrow-down-fill"></i> <span class="d-none d-md-inline">Download</span> aria-expanded="false">
</a> <i class="bi bi-file-arrow-down-fill"></i>
<span class="d-none d-md-inline ms-1">Download</span>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<a :href="'api/v1/message/' + message.ID + '/raw?dl=1'" class="dropdown-item"
title="Message source including headers, body and attachments">
Raw message
</a>
</li>
<li v-if="message.HTML">
<button v-on:click="downloadMessageBody(message.HTML, 'html')" class="dropdown-item">
HTML body
</button>
</li>
<li v-if="message.Text">
<button v-on:click="downloadMessageBody(message.Text, 'txt')" class="dropdown-item">
Text body
</button>
</li>
<li v-if="allAttachments(message).length">
<hr class="dropdown-divider">
</li>
<li v-for="part in allAttachments(message)">
<a :href="'api/v1/message/' + message.ID + '/part/' + part.PartID" type="button"
class="row m-0 dropdown-item d-flex" target="_blank"
:title="part.FileName != '' ? part.FileName : '[ unknown ]'" style="min-width: 350px">
<div class="col-auto p-0 pe-1">
<i class="bi" :class="attachmentIcon(part)"></i>
</div>
<div class="col text-truncate p-0 pe-1">
{{ part.FileName != '' ? part.FileName : '[ unknown ]' }}
</div>
<div class="col-auto text-muted small p-0">
{{ getFileSize(part.Size) }}
</div>
</a>
</li>
</ul>
</div>
</div> </div>
<div class="col col-md-9 col-lg-5" v-if="!message"> <div class="col col-md-9 col-lg-5" v-if="!message">
@ -617,6 +664,7 @@ export default {
<option value="100">100</option> <option value="100">100</option>
<option value="200">200</option> <option value="200">200</option>
</select> </select>
<span v-if="searching"> <span v-if="searching">
<b>{{ formatNumber(items.length) }} result<template v-if="items.length != 1">s</template></b> <b>{{ formatNumber(items.length) }} result<template v-if="items.length != 1">s</template></b>
</span> </span>
@ -678,16 +726,16 @@ export default {
<button class="list-group-item list-group-item-action" :disabled="!selectedHasUnread()" <button class="list-group-item list-group-item-action" :disabled="!selectedHasUnread()"
v-on:click="markSelectedRead"> v-on:click="markSelectedRead">
<i class="bi bi-eye-fill"></i> <i class="bi bi-eye-fill"></i>
Mark selected read Mark read
</button> </button>
<button class="list-group-item list-group-item-action" :disabled="!selectedHasRead()" <button class="list-group-item list-group-item-action" :disabled="!selectedHasRead()"
v-on:click="markSelectedUnread"> v-on:click="markSelectedUnread">
<i class="bi bi-eye-slash"></i> <i class="bi bi-eye-slash"></i>
Mark selected unread Mark unread
</button> </button>
<button class="list-group-item list-group-item-action" v-on:click="deleteMessages"> <button class="list-group-item list-group-item-action" v-on:click="deleteMessages">
<i class="bi bi-trash-fill me-1 text-danger"></i> <i class="bi bi-trash-fill me-1 text-danger"></i>
Delete selected Delete
</button> </button>
<button class="list-group-item list-group-item-action" v-on:click="selected = []"> <button class="list-group-item list-group-item-action" v-on:click="selected = []">
<i class="bi bi-x-circle me-1"></i> <i class="bi bi-x-circle me-1"></i>

View File

@ -149,10 +149,6 @@ body.blur {
} }
} }
// .tag.active {
// font-weight: bold;
// }
.form-select.tag-selector { .form-select.tag-selector {
display: none; display: none;
} }
@ -166,6 +162,17 @@ body.blur {
} }
} }
#DownloadBtn {
@include media-breakpoint-down(sm) {
position: static;
.dropdown-menu {
left: 0;
right: 0;
}
}
}
/* PrismJS 1.29.0 - modified! /* PrismJS 1.29.0 - modified!
https://prismjs.com/download.html#themes=prism-coy&languages=markup+css */ https://prismjs.com/download.html#themes=prism-coy&languages=markup+css */
code[class*="language-"], code[class*="language-"],

View File

@ -211,25 +211,12 @@ export default {
</tbody> </tbody>
</table> </table>
</div> </div>
<div class="col-md-auto text-md-end mt-md-3"> <div class="col-md-auto d-none d-md-block text-end mt-md-3">
<!-- <p class="text-muted small d-none d-md-block mb-2"><small>{{ messageDate(message.Date) }}</small></p> <div class="mt-2 mt-md-0" v-if="allAttachments(message)">
<p class="text-muted small d-none d-md-block"><small>Size: {{ getFileSize(message.Size) }}</small></p> --> <span class="badge rounded-pill text-bg-secondary p-2">
<div class="dropdown mt-2 mt-md-0" v-if="allAttachments(message)">
<button class="btn btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown"
aria-expanded="false">
Attachment<span v-if="allAttachments(message).length > 1">s</span> Attachment<span v-if="allAttachments(message).length > 1">s</span>
({{ allAttachments(message).length }}) ({{ allAttachments(message).length }})
</button> </span>
<ul class="dropdown-menu">
<li v-for="part in allAttachments(message)">
<a :href="'api/v1/message/' + message.ID + '/part/' + part.PartID" type="button"
class="dropdown-item" target="_blank">
<i class="bi" :class="attachmentIcon(part)"></i>
{{ part.FileName != '' ? part.FileName : '[ unknown ]' }}
<small class="text-muted ms-2">{{ getFileSize(part.Size) }}</small>
</a>
</li>
</ul>
</div> </div>
</div> </div>
</div> </div>