Allow sending emails to self

This commit is contained in:
Andris Reinman 2017-12-15 14:26:29 +02:00
parent 3970ac7dba
commit e6bdfadac2
2 changed files with 166 additions and 153 deletions

2
api.js
View file

@ -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 => {

View file

@ -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);
}