mirror of
https://github.com/nodemailer/wildduck.git
synced 2024-11-10 17:47:07 +08:00
Allow sending emails to self
This commit is contained in:
parent
3970ac7dba
commit
e6bdfadac2
2 changed files with 166 additions and 153 deletions
2
api.js
2
api.js
|
@ -141,7 +141,7 @@ module.exports = done => {
|
|||
updatesRoutes(db, server, notifier);
|
||||
authRoutes(db, server, userHandler);
|
||||
autoreplyRoutes(db, server);
|
||||
submitRoutes(db, server, messageHandler);
|
||||
submitRoutes(db, server, messageHandler, userHandler);
|
||||
domainaliasRoutes(db, server);
|
||||
|
||||
server.on('error', err => {
|
||||
|
|
|
@ -24,7 +24,7 @@ class StreamCollect extends Transform {
|
|||
}
|
||||
}
|
||||
|
||||
module.exports = (db, server, messageHandler) => {
|
||||
module.exports = (db, server, messageHandler, userHandler) => {
|
||||
function submitMessage(options, callback) {
|
||||
let user = options.user;
|
||||
|
||||
|
@ -64,162 +64,182 @@ module.exports = (db, server, messageHandler) => {
|
|||
let overQuota = Number(userData.quota || config.maxStorage * 1024 * 1024) - userData.storageUsed <= 0;
|
||||
userData.recipients = userData.recipients || config.maxRecipients;
|
||||
|
||||
db.users
|
||||
.collection('addresses')
|
||||
.find({ user: userData._id }, { address: true, addrview: true })
|
||||
.toArray((err, addresses) => {
|
||||
if (err) {
|
||||
err.code = 'ERRDB';
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
let getReferencedMessage = done => {
|
||||
if (!options.reference) {
|
||||
return done(null, false);
|
||||
let getReferencedMessage = done => {
|
||||
if (!options.reference) {
|
||||
return done(null, false);
|
||||
}
|
||||
let query = {};
|
||||
if (typeof options.reference === 'object') {
|
||||
query.mailbox = options.reference.mailbox;
|
||||
query.uid = options.reference.id;
|
||||
} else {
|
||||
return done(null, false);
|
||||
}
|
||||
query.user = user;
|
||||
db.users.collection('messages').findOne(
|
||||
query,
|
||||
{
|
||||
fields: {
|
||||
'mimeTree.parsedHeader': true,
|
||||
thread: true
|
||||
}
|
||||
let query = {};
|
||||
if (typeof options.reference === 'object') {
|
||||
query.mailbox = options.reference.mailbox;
|
||||
query.uid = options.reference.id;
|
||||
} else {
|
||||
return done(null, false);
|
||||
}
|
||||
query.user = user;
|
||||
db.users.collection('messages').findOne(
|
||||
query,
|
||||
{
|
||||
fields: {
|
||||
'mimeTree.parsedHeader': true,
|
||||
thread: true
|
||||
}
|
||||
},
|
||||
(err, messageData) => {
|
||||
if (err) {
|
||||
err.code = 'ERRDB';
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
let headers = (messageData && messageData.mimeTree && messageData.mimeTree.parsedHeader) || {};
|
||||
let subject = headers.subject || '';
|
||||
try {
|
||||
subject = libmime.decodeWords(subject).trim();
|
||||
} catch (E) {
|
||||
// failed to parse value
|
||||
}
|
||||
|
||||
if (!/^\w+: /.test(subject)) {
|
||||
subject = ((options.reference.action === 'forward' ? 'Fwd' : 'Re') + ': ' + subject).trim();
|
||||
}
|
||||
|
||||
let sender = headers['reply-to'] || headers.from || headers.sender;
|
||||
let replyTo = [];
|
||||
let replyCc = [];
|
||||
let uniqueRecipients = new Set();
|
||||
|
||||
let checkAddress = (target, addr) => {
|
||||
let address = tools.normalizeAddress(addr.address);
|
||||
if (!inAddressList(addresses, address) && !uniqueRecipients.has(address)) {
|
||||
uniqueRecipients.add(address);
|
||||
if (addr.name) {
|
||||
try {
|
||||
addr.name = libmime.decodeWords(addr.name).trim();
|
||||
} catch (E) {
|
||||
// failed to parse value
|
||||
}
|
||||
}
|
||||
target.push(addr);
|
||||
}
|
||||
};
|
||||
|
||||
if (sender && sender.address) {
|
||||
checkAddress(replyTo, sender);
|
||||
}
|
||||
|
||||
if (options.reference.action === 'replyAll') {
|
||||
[].concat(headers.to || []).forEach(addr => {
|
||||
let walk = addr => {
|
||||
if (addr.address) {
|
||||
checkAddress(replyTo, addr);
|
||||
} else if (addr.group) {
|
||||
addr.group.forEach(walk);
|
||||
}
|
||||
};
|
||||
walk(addr);
|
||||
});
|
||||
[].concat(headers.cc || []).forEach(addr => {
|
||||
let walk = addr => {
|
||||
if (addr.address) {
|
||||
checkAddress(replyCc, addr);
|
||||
} else if (addr.group) {
|
||||
addr.group.forEach(walk);
|
||||
}
|
||||
};
|
||||
walk(addr);
|
||||
});
|
||||
}
|
||||
|
||||
let messageId = (headers['message-id'] || '').trim();
|
||||
let references = (headers.references || '')
|
||||
.trim()
|
||||
.replace(/\s+/g, ' ')
|
||||
.split(' ')
|
||||
.filter(mid => mid);
|
||||
|
||||
if (messageId && !references.includes(messageId)) {
|
||||
references.unshift(messageId);
|
||||
}
|
||||
if (references.length > 50) {
|
||||
references = references.slice(0, 50);
|
||||
}
|
||||
|
||||
let referenceData = {
|
||||
replyTo,
|
||||
replyCc,
|
||||
subject,
|
||||
thread: messageData.thread,
|
||||
inReplyTo: messageId,
|
||||
references: references.join(' ')
|
||||
};
|
||||
|
||||
return done(null, referenceData);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
getReferencedMessage((err, referenceData) => {
|
||||
},
|
||||
(err, messageData) => {
|
||||
if (err) {
|
||||
err.code = 'ERRDB';
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
let envelope = options.envelope;
|
||||
|
||||
if (!envelope) {
|
||||
envelope = {
|
||||
from: options.from,
|
||||
to: []
|
||||
};
|
||||
let headers = (messageData && messageData.mimeTree && messageData.mimeTree.parsedHeader) || {};
|
||||
let subject = headers.subject || '';
|
||||
try {
|
||||
subject = libmime.decodeWords(subject).trim();
|
||||
} catch (E) {
|
||||
// failed to parse value
|
||||
}
|
||||
|
||||
if (!envelope.from) {
|
||||
if (options.from) {
|
||||
envelope.from = options.from;
|
||||
} else {
|
||||
options.from = envelope.from = {
|
||||
name: userData.name || '',
|
||||
address: userData.address
|
||||
};
|
||||
if (!/^\w+: /.test(subject)) {
|
||||
subject = ((options.reference.action === 'forward' ? 'Fwd' : 'Re') + ': ' + subject).trim();
|
||||
}
|
||||
|
||||
let sender = headers['reply-to'] || headers.from || headers.sender;
|
||||
let replyTo = [];
|
||||
let replyCc = [];
|
||||
let uniqueRecipients = new Set();
|
||||
|
||||
let checkAddress = (target, addr) => {
|
||||
let address = tools.normalizeAddress(addr.address);
|
||||
|
||||
if (address !== userData.address && !uniqueRecipients.has(address)) {
|
||||
uniqueRecipients.add(address);
|
||||
if (addr.name) {
|
||||
try {
|
||||
addr.name = libmime.decodeWords(addr.name).trim();
|
||||
} catch (E) {
|
||||
// failed to parse value
|
||||
}
|
||||
}
|
||||
target.push(addr);
|
||||
}
|
||||
};
|
||||
|
||||
if (sender && sender.address) {
|
||||
checkAddress(replyTo, sender);
|
||||
}
|
||||
|
||||
options.from = options.from || envelope.from;
|
||||
|
||||
if (!inAddressList(addresses, tools.normalizeAddress(options.from.address))) {
|
||||
options.from.address = userData.address;
|
||||
if (options.reference.action === 'replyAll') {
|
||||
[].concat(headers.to || []).forEach(addr => {
|
||||
let walk = addr => {
|
||||
if (addr.address) {
|
||||
checkAddress(replyTo, addr);
|
||||
} else if (addr.group) {
|
||||
addr.group.forEach(walk);
|
||||
}
|
||||
};
|
||||
walk(addr);
|
||||
});
|
||||
[].concat(headers.cc || []).forEach(addr => {
|
||||
let walk = addr => {
|
||||
if (addr.address) {
|
||||
checkAddress(replyCc, addr);
|
||||
} else if (addr.group) {
|
||||
addr.group.forEach(walk);
|
||||
}
|
||||
};
|
||||
walk(addr);
|
||||
});
|
||||
}
|
||||
|
||||
if (!inAddressList(addresses, tools.normalizeAddress(envelope.from.address))) {
|
||||
envelope.from.address = userData.address;
|
||||
let messageId = (headers['message-id'] || '').trim();
|
||||
let references = (headers.references || '')
|
||||
.trim()
|
||||
.replace(/\s+/g, ' ')
|
||||
.split(' ')
|
||||
.filter(mid => mid);
|
||||
|
||||
if (messageId && !references.includes(messageId)) {
|
||||
references.unshift(messageId);
|
||||
}
|
||||
if (references.length > 50) {
|
||||
references = references.slice(0, 50);
|
||||
}
|
||||
|
||||
let referenceData = {
|
||||
replyTo,
|
||||
replyCc,
|
||||
subject,
|
||||
thread: messageData.thread,
|
||||
inReplyTo: messageId,
|
||||
references: references.join(' ')
|
||||
};
|
||||
|
||||
return done(null, referenceData);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
getReferencedMessage((err, referenceData) => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
let envelope = options.envelope;
|
||||
|
||||
if (!envelope) {
|
||||
envelope = {
|
||||
from: options.from,
|
||||
to: []
|
||||
};
|
||||
}
|
||||
|
||||
if (!envelope.from) {
|
||||
if (options.from) {
|
||||
envelope.from = options.from;
|
||||
} else {
|
||||
options.from = envelope.from = {
|
||||
name: userData.name || '',
|
||||
address: userData.address
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
options.from = options.from || envelope.from;
|
||||
|
||||
let validateFromAddress = (address, next) => {
|
||||
if (options.uploadOnly) {
|
||||
// message is not sent, so we do not care if address is valid or not
|
||||
return next(null, address);
|
||||
}
|
||||
|
||||
if (!address || address === userData.address) {
|
||||
// using default address, ok
|
||||
return next(null, userData.address);
|
||||
}
|
||||
|
||||
userHandler.get(address, false, (err, resolvedUser) => {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
if (!resolvedUser || resolvedUser._id.toString() !== userData._id.toString()) {
|
||||
return next(null, userData.address);
|
||||
}
|
||||
return next(null, address);
|
||||
});
|
||||
};
|
||||
|
||||
// make sure that envelope address is allowed for current user
|
||||
validateFromAddress(tools.normalizeAddress(envelope.from.address), (err, address) => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
envelope.from.address = address;
|
||||
|
||||
// make sure that message header address is allowed for current user
|
||||
validateFromAddress(tools.normalizeAddress(options.from.address), (err, address) => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
options.from.address = address;
|
||||
|
||||
if (!envelope.to.length) {
|
||||
envelope.to = envelope.to
|
||||
|
@ -243,8 +263,6 @@ module.exports = (db, server, messageHandler) => {
|
|||
}
|
||||
}
|
||||
|
||||
envelope.to = envelope.to.filter(addr => !inAddressList(addresses, tools.normalizeAddress(addr.address)));
|
||||
|
||||
let now = new Date();
|
||||
let sendTime = options.sendTime;
|
||||
if (!sendTime || sendTime < now) {
|
||||
|
@ -428,6 +446,7 @@ module.exports = (db, server, messageHandler) => {
|
|||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -735,9 +754,3 @@ module.exports = (db, server, messageHandler) => {
|
|||
});
|
||||
});
|
||||
};
|
||||
|
||||
function inAddressList(addresses, address) {
|
||||
let addrview = address.substr(0, address.indexOf('@')).replace(/\./g, '') + address.substr(address.indexOf('@'));
|
||||
|
||||
return !!addresses.find(addr => addr.addrview === addrview);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue