Software: Apache/2.4.41 (Ubuntu). PHP/8.0.30 uname -a: Linux apirnd 5.4.0-204-generic #224-Ubuntu SMP Thu Dec 5 13:38:28 UTC 2024 x86_64 uid=33(www-data) gid=33(www-data) groups=33(www-data) Safe-mode: OFF (not secure) /var/www/html/wincloud_gateway/node_modules/sendmail/ drwxr-xr-x | |
| Viewing file: Select action/file-type: const {createConnection} = require('net');
const {resolveMx} = require('dns');
const {DKIMSign} = require('dkim-signer');
const CRLF = '\r\n';
function dummy () {}
module.exports = function (options) {
options = options || {};
const logger = options.logger || (options.silent && {
debug: dummy,
info: dummy,
warn: dummy,
error: dummy
} || {
debug: console.log,
info: console.info,
warn: console.warn,
error: console.error
});
const dkimPrivateKey = (options.dkim || {}).privateKey;
const dkimKeySelector = (options.dkim || {}).keySelector || 'dkim';
const devPort = options.devPort || -1;
const devHost = options.devHost || 'localhost';
const smtpPort = options.smtpPort || 25
const smtpHost = options.smtpHost || -1
/*
* 邮件服务返回代码含义 Mail service return code Meaning
* 500 格式错误,命令不可识别(此错误也包括命令行过长)format error, command unrecognized (This error also includes command line too long)
* 501 参数格式错误 parameter format error
* 502 命令不可实现 command can not be achieved
* 503 错误的命令序列 Bad sequence of commands
* 504 命令参数不可实现 command parameter can not be achieved
* 211 系统状态或系统帮助响应 System status, or system help response
* 214 帮助信息 help
* 220 服务就绪 Services Ready
* 221 服务关闭传输信道 Service closing transmission channel
* 421 服务未就绪,关闭传输信道(当必须关闭时,此应答可以作为对任何命令的响应)service is not ready to close the transmission channel (when it is necessary to close, this response may be in response to any command)
* 250 要求的邮件操作完成 requested mail action completed
* 251 用户非本地,将转发向 non-local users will be forwarded to
* 450 要求的邮件操作未完成,邮箱不可用(例如,邮箱忙)Mail the required operation 450 unfinished, mailbox unavailable (for example, mailbox busy)
* 550 要求的邮件操作未完成,邮箱不可用(例如,邮箱未找到,或不可访问)Mail action not completed the required 550 mailbox unavailable (eg, mailbox not found, no access)
* 451 放弃要求的操作;处理过程中出错 waiver operation; processing error
* 551 用户非本地,请尝试 non-local user, please try
* 452 系统存储不足,要求的操作未执行 Less than 452 storage system, requiring action not taken
* 552 过量的存储分配,要求的操作未执行 excess storage allocation requires action not taken
* 553 邮箱名不可用,要求的操作未执行(例如邮箱格式错误) mailbox name is not available, that the requested operation is not performed (for example, mailbox format error)
* 354 开始邮件输入,以.结束 Start Mail input to. End
* 554 操作失败 The operation failed
* 535 用户验证失败 User authentication failed
* 235 用户验证成功 user authentication is successful
* 334 等待用户输入验证信息 waits for the user to enter authentication information
*/
function getHost (email) {
const m = /[^@]+@([\w\d\-\.]+)/.exec(email);
return m && m[1];
}
function groupRecipients (recipients) {
let groups = {};
let host;
const recipients_length = recipients.length;
for (let i = 0; i < recipients_length; i++) {
host = getHost(recipients[i]);
(groups[host] || (groups[host] = [])).push(recipients[i])
}
return groups
}
/**
* connect to domain by Mx record
*/
function connectMx (domain, callback) {
if (devPort === -1) { // not in development mode -> search the MX
resolveMx(domain, function (err, data) {
if (err) {
return callback(err)
}
data.sort(function (a, b) { return a.priority > b.priority });
logger.debug('mx resolved: ', data);
if (!data || data.length === 0) {
return callback(new Error('can not resolve Mx of <' + domain + '>'))
}
if(smtpHost !== -1)data.push({exchange:smtpHost})
function tryConnect (i) {
if (i >= data.length) return callback(new Error('can not connect to any SMTP server'));
const sock = createConnection(smtpPort, data[i].exchange);
sock.on('error', function (err) {
logger.error('Error on connectMx for: ', data[i], err);
tryConnect(++i)
});
sock.on('connect', function () {
logger.debug('MX connection created: ', data[i].exchange);
sock.removeAllListeners('error');
callback(null, sock)
})
}
tryConnect(0)
})
} else { // development mode -> connect to the specified devPort on devHost
const sock = createConnection(devPort, devHost);
sock.on('error', function (err) {
callback(new Error('Error on connectMx (development) for "'+ devHost +':' + devPort + '": ' + err))
});
sock.on('connect', function () {
logger.debug('MX (development) connection created: '+ devHost +':' + devPort);
sock.removeAllListeners('error');
callback(null, sock)
})
}
}
function sendToSMTP (domain, srcHost, from, recipients, body, cb) {
const callback = (typeof cb === 'function') ? cb : function () {};
connectMx(domain, function (err, sock) {
if (err) {
logger.error('error on connectMx', err.stack);
return callback(err)
}
function w (s) {
logger.debug('send ' + domain + '>' + s);
sock.write(s + CRLF)
}
sock.setEncoding('utf8');
sock.on('data', function (chunk) {
data += chunk;
parts = data.split(CRLF);
const parts_length = parts.length - 1;
for (let i = 0, len = parts_length; i < len; i++) {
onLine(parts[i])
}
data = parts[parts.length - 1]
});
sock.on('error', function (err) {
logger.error('fail to connect ' + domain)
callback(err)
});
let data = '';
let step = 0;
let loginStep = 0;
const queue = [];
const login = [];
let parts;
let cmd;
/*
if(mail.user && mail.pass){
queue.push('AUTH LOGIN');
login.push(new Buffer(mail.user).toString("base64"));
login.push(new Buffer(mail.pass).toString("base64"));
}
*/
queue.push('MAIL FROM:<' + from + '>');
const recipients_length = recipients.length;
for (let i = 0; i < recipients_length; i++) {
queue.push('RCPT TO:<' + recipients[i] + '>')
}
queue.push('DATA');
queue.push('QUIT');
queue.push('');
function response (code, msg) {
switch (code) {
case 220:
//* 220 on server ready
//* 220 服务就绪
if (/\besmtp\b/i.test(msg)) {
// TODO: determin AUTH type; auth login, auth crm-md5, auth plain
cmd = 'EHLO'
} else {
cmd = 'HELO'
}
w(cmd + ' ' + srcHost);
break;
case 221: // bye
case 235: // verify ok
case 250: // operation OK
case 251: // foward
if (step === queue.length - 1) {
logger.info('OK:', code, msg);
callback(null, msg)
}
w(queue[step]);
step++;
break;
case 354: // start input end with . (dot)
logger.info('sending mail', body);
w(body);
w('');
w('.');
break;
case 334: // input login
w(login[loginStep]);
loginStep++;
break;
default:
if (code >= 400) {
logger.warn('SMTP responds error code', code);
callback(new Error('SMTP code:' + code + ' msg:' + msg));
sock.end();
}
}
}
let msg = '';
function onLine (line) {
logger.debug('recv ' + domain + '>' + line);
msg += (line + CRLF);
if (line[3] === ' ') {
// 250-information dash is not complete.
// 250 OK. space is complete.
let lineNumber = parseInt(line);
response(lineNumber, msg);
msg = '';
}
}
})
}
function getAddress (address) {
return address.replace(/^.+</, '').replace(/>\s*$/, '').trim();
}
function getAddresses (addresses) {
const results = [];
if (!Array.isArray(addresses)) {
addresses = addresses.split(',');
}
const addresses_length = addresses.length;
for (let i = 0; i < addresses_length; i++) {
results.push(getAddress(addresses[i]));
}
return results
}
/**
* sendmail directly
*
* @param mail {object}
* from
* to
* cc
* bcc
* replyTo
* returnTo
* subject
* type default 'text/plain', 'text/html'
* charset default 'utf-8'
* encoding default 'base64'
* id default timestamp+from
* headers object
* content
* attachments
* [{
* type
* filename
* content
* }].
*
* @param callback function(err, domain).
*
*/
function sendmail (mail, callback) {
const mailcomposer = require('mailcomposer');
const mailMe = mailcomposer(mail);
let recipients = [];
let groups;
let srcHost;
if (mail.to) {
recipients = recipients.concat(getAddresses(mail.to))
}
if (mail.cc) {
recipients = recipients.concat(getAddresses(mail.cc))
}
if (mail.bcc) {
recipients = recipients.concat(getAddresses(mail.bcc))
}
groups = groupRecipients(recipients);
const from = getAddress(mail.from);
srcHost = getHost(from);
mailMe.build(function (err, message) {
if (err) {
logger.error('Error on creating message : ', err)
callback(err, null);
return
}
if (dkimPrivateKey) {
const signature = DKIMSign(message, {
privateKey: dkimPrivateKey,
keySelector: dkimKeySelector,
domainName: srcHost
});
message = signature + '\r\n' + message
}
for (let domain in groups) {
sendToSMTP(domain, srcHost, from, groups[domain], message, callback)
}
});
}
return sendmail
};
|
:: Command execute :: | |
--[ c99shell v. 2.5 [PHP 8 Update] [24.05.2025] | Generation time: 0.0042 ]-- |