Merge branch 'master' of github.com:nodemailer/wildduck

This commit is contained in:
Andris Reinman 2024-04-29 13:18:05 +03:00
commit 5af8f24ddb
No known key found for this signature in database
GPG key ID: DC6C83F4D584D364
4 changed files with 121 additions and 107 deletions

View file

@ -1,5 +1,18 @@
# Changelog # Changelog
## [1.43.0](https://github.com/nodemailer/wildduck/compare/v1.42.6...v1.43.0) (2024-04-29)
### Features
* **autoacme:** Allow setting up automatic ACME certificate generation ([cd8596a](https://github.com/nodemailer/wildduck/commit/cd8596a84d36f9870858f3fdc4249f2af42347d9))
* **SNI:** Autogenerate TLS certificates for SNI ([40db519](https://github.com/nodemailer/wildduck/commit/40db519d9c08ebe588a6ce820f6287d4f52f038f))
### Bug Fixes
* **SNI:** delete expired autogenerated SNI certificate ([61c03e1](https://github.com/nodemailer/wildduck/commit/61c03e1725c68fcb0c41e505b4d8cb80b0d73d15))
## [1.42.6](https://github.com/nodemailer/wildduck/compare/v1.42.5...v1.42.6) (2024-04-22) ## [1.42.6](https://github.com/nodemailer/wildduck/compare/v1.42.5...v1.42.6) (2024-04-22)

View file

@ -12,8 +12,11 @@ const tools = require('../tools');
const Maildropper = require('../maildropper'); const Maildropper = require('../maildropper');
const roles = require('../roles'); const roles = require('../roles');
const Transform = require('stream').Transform; const Transform = require('stream').Transform;
const { sessSchema, sessIPSchema, booleanSchema } = require('../schemas'); const { sessSchema, sessIPSchema, booleanSchema, metaDataSchema } = require('../schemas');
const { preprocessAttachments } = require('../data-url'); const { preprocessAttachments } = require('../data-url');
const { userId, mailboxId } = require('../schemas/request/general-schemas');
const { AddressOptionalName, AddressOptionalNameArray, Header, Attachment, ReferenceWithAttachments } = require('../schemas/request/messages-schemas');
const { successRes } = require('../schemas/response/general-schemas');
class StreamCollect extends Transform { class StreamCollect extends Transform {
constructor() { constructor() {
@ -620,113 +623,111 @@ module.exports = (db, server, messageHandler, userHandler, settingsHandler) => {
const submitMessageWrapper = util.promisify(submitMessage); const submitMessageWrapper = util.promisify(submitMessage);
server.post( server.post(
{ name: 'send', path: '/users/:user/submit' }, {
name: 'send',
path: '/users/:user/submit',
tags: ['Submission'],
summary: 'Submit a Message for Delivery',
description: 'Use this method to send emails from a user account',
validationObjs: {
requestBody: {
mailbox: mailboxId,
from: AddressOptionalName.description('Addres for the From: header'),
replyTo: AddressOptionalName.description('Address for the Reply-To: header'),
to: Joi.array()
.items(
Joi.object({
name: Joi.string().empty('').max(255).description('Name of the sender'),
address: Joi.string().email({ tlds: false }).failover('').required().description('Address of the sender')
}).$_setFlag('objectName', 'AddressOptionalName')
)
.description('Addresses for the To: header'),
cc: AddressOptionalNameArray.description('Addresses for the Cc: header'),
bcc: AddressOptionalNameArray.description('Addresses for the Bcc: header'),
headers: Joi.array()
.items(Header)
.description(
'Custom headers for the message. If reference message is set then In-Reply-To and References headers are set automatically'
),
subject: Joi.string()
.empty('')
.max(2 * 1024)
.description('Message subject. If not then resolved from Reference message'),
text: Joi.string()
.empty('')
.max(1024 * 1024)
.description('Plaintext message'),
html: Joi.string()
.empty('')
.max(1024 * 1024)
.description('HTML formatted message'),
attachments: Joi.array().items(Attachment).description('Attachments for the message'),
meta: metaDataSchema.label('metaData').description('Optional metadata, must be an object or JSON formatted string'),
sess: sessSchema,
ip: sessIPSchema,
reference: ReferenceWithAttachments.description(
'Optional referenced email. If uploaded message is a reply draft and relevant fields are not provided then these are resolved from the message to be replied to'
),
// if true then treat this message as a draft
isDraft: booleanSchema.default(false).description('Is the message a draft or not'),
// if set then this message is based on a draft that should be deleted after processing
draft: Joi.object()
.keys({
mailbox: mailboxId,
id: Joi.number().required().description('Message ID')
})
.description('Draft message to base this one on'),
sendTime: Joi.date().description('Send time'),
uploadOnly: booleanSchema.default(false).description('If true only uploads the message but does not send it'),
envelope: Joi.object()
.keys({
from: AddressOptionalName.description('Addres for the From: header'),
to: Joi.array().items(
Joi.object()
.keys({
name: Joi.string().empty('').max(255).description('Name of the sender'),
address: Joi.string().email({ tlds: false }).required().description('Address of the sender')
})
.description('Addresses for the To: header')
)
})
.description('Optional envelope')
},
queryParams: {},
pathParams: {
user: userId
},
response: {
200: {
description: 'Success',
model: Joi.object({
success: successRes,
message: Joi.object({
mailbox: Joi.string().required().description('Mailbox ID the message was stored to'),
id: Joi.number().description('Message ID in the Mailbox').required(),
queueId: Joi.string().required().description('Queue ID in MTA')
})
.required()
.description('Information about submitted Message')
.$_setFlag('objectName', 'MessageWithQueueId')
})
}
}
}
},
tools.responseWrapper(async (req, res) => { tools.responseWrapper(async (req, res) => {
res.charSet('utf-8'); res.charSet('utf-8');
const schema = Joi.object().keys({ const { pathParams, requestBody, queryParams } = req.route.spec.validationObjs;
user: Joi.string().hex().lowercase().length(24).required(),
mailbox: Joi.string().hex().lowercase().length(24), const schema = Joi.object({
...pathParams,
reference: Joi.object().keys({ ...requestBody,
mailbox: Joi.string().hex().lowercase().length(24).required(), ...queryParams
id: Joi.number().required(),
action: Joi.string().valid('reply', 'replyAll', 'forward').required()
}),
// if true then treat this message as a draft
isDraft: booleanSchema.default(false),
// if set then this message is based on a draft that should be deleted after processing
draft: Joi.object().keys({
mailbox: Joi.string().hex().lowercase().length(24).required(),
id: Joi.number().required()
}),
uploadOnly: booleanSchema.default(false),
sendTime: Joi.date(),
envelope: Joi.object().keys({
from: Joi.object().keys({
name: Joi.string().empty('').max(255),
address: Joi.string().email({ tlds: false }).required()
}),
to: Joi.array().items(
Joi.object().keys({
name: Joi.string().empty('').max(255),
address: Joi.string().email({ tlds: false }).required()
})
)
}),
from: Joi.object().keys({
name: Joi.string().empty('').max(255),
address: Joi.string().email({ tlds: false }).required()
}),
replyTo: Joi.object().keys({
name: Joi.string().empty('').max(255),
address: Joi.string().email({ tlds: false }).required()
}),
to: Joi.array().items(
Joi.object().keys({
name: Joi.string().empty('').max(255),
address: Joi.string().email({ tlds: false }).required()
})
),
cc: Joi.array().items(
Joi.object().keys({
name: Joi.string().empty('').max(255),
address: Joi.string().email({ tlds: false }).required()
})
),
bcc: Joi.array().items(
Joi.object().keys({
name: Joi.string().empty('').max(255),
address: Joi.string().email({ tlds: false }).required()
})
),
headers: Joi.array().items(
Joi.object().keys({
key: Joi.string().empty('').max(255),
value: Joi.string()
.empty('')
.max(100 * 1024)
})
),
subject: Joi.string()
.empty('')
.max(2 * 1024),
text: Joi.string()
.empty('')
.max(1024 * 1024),
html: Joi.string()
.empty('')
.max(1024 * 1024),
attachments: Joi.array().items(
Joi.object().keys({
filename: Joi.string().empty('').max(255),
contentType: Joi.string().empty('').max(255),
contentTransferEncoding: Joi.string().empty('').trim().lowercase(),
contentDisposition: Joi.string().empty('').trim().lowercase().valid('inline', 'attachment'),
cid: Joi.string().empty('').max(255),
encoding: Joi.string().empty('').default('base64'),
content: Joi.string().required()
})
),
meta: Joi.object().unknown(true),
sess: sessSchema,
ip: sessIPSchema
}); });
// extract embedded attachments from HTML // extract embedded attachments from HTML

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "wildduck", "name": "wildduck",
"version": "1.42.6", "version": "1.43.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "wildduck", "name": "wildduck",
"version": "1.42.6", "version": "1.43.0",
"license": "EUPL-1.2", "license": "EUPL-1.2",
"dependencies": { "dependencies": {
"@fidm/x509": "1.2.1", "@fidm/x509": "1.2.1",

View file

@ -1,6 +1,6 @@
{ {
"name": "wildduck", "name": "wildduck",
"version": "1.42.6", "version": "1.43.0",
"description": "IMAP/POP3 server built with Node.js and MongoDB", "description": "IMAP/POP3 server built with Node.js and MongoDB",
"main": "server.js", "main": "server.js",
"scripts": { "scripts": {