diff --git a/credentials.default.json b/credentials.default.json index 553de09..22f126c 100644 --- a/credentials.default.json +++ b/credentials.default.json @@ -1,8 +1,15 @@ { "user": "mail@domein.tld", "password": "wachtwoord", - "host": "imap.domein.tld", - "port": 993, - "tls": true, + "imap": { + "host": "imap.domein.tld", + "port": 993, + "tls": true + }, + "smtp": { + "host": "smtp.domein.tld", + "port": 465, + "tls": true + }, "authTimeout": 5000 } \ No newline at end of file diff --git a/html/index.html b/html/index.html index 34c00a8..bbcbe2e 100644 --- a/html/index.html +++ b/html/index.html @@ -21,7 +21,7 @@ - IMAP Credentials + Credentials Mail Processing Chain Notification Configuration @@ -36,15 +36,28 @@ + IMAP: - + - + - + + + + SMTP: + + + + + + + + + @@ -68,6 +81,7 @@
Index: {{ index }}
+ mdi-delete @@ -79,7 +93,7 @@
possible Placeholders: [from] [fromName] [fromAddress] [subject]
- +
@@ -204,6 +218,7 @@ storeConfig.handling.processing = storeConfig.handling.processing.map(x => { let y = { } if (!!x.ignore && x.ignore == true) y.ignore = true + if (!!x.duplexReply && x.duplexReply == true) y.duplexReply = true if (!!x.format && x.format.length > 0) y.format = x.format for (n of ['format', 'subjectContains', 'mxdomainExact', 'mxdomainContains']) // only copy if not empty if (!!x[n] && x[n].length > 0) y[n] = x[n] diff --git a/index.js b/index.js index 6068269..7b0aac7 100644 --- a/index.js +++ b/index.js @@ -1,32 +1,98 @@ +const MailListener = require("mail-listener2") const ImapSimple = require('imap-simple') const mailparser = require('mailparser') const fs = require('fs') if (!fs.existsSync('./credentials.json')) fs.copyFileSync('./credentials.default.json', './credentials.json') let $ImapConnection + const config = require('./config.json') -config.imap = require('./credentials.json') +const credentials = require('./credentials.json') + +const nodemailer = require("nodemailer") +config.smtp = Object.assign({}, credentials, credentials.smtp) +let smtpTransporter = nodemailer.createTransport({ + host: config.smtp.host, + port: config.smtp.port, + secure: config.smtp.tls, + auth: { + user: config.smtp.user, // generated ethereal user + pass: config.smtp.password, // generated ethereal password + }, +}) + +config.imap = Object.assign({}, credentials, credentials.imap) + +config.imap.username = config.imap.user //config.onmail = () => ScanUnread() +const io = require("socket.io-client") const axios = require('axios') +const socket = io(new URL(config.pager.url).origin) + +const mailListener = new MailListener({ + ...config.imap, + connTimeout: 10000, + authTimeout: 10000, + //debug: console.log, + tlsOptions: { rejectUnauthorized: false }, + mailbox: "INBOX", + searchFilter: ["UNSEEN"], + markSeen: true, + fetchUnreadOnStart: true, +}) + const searchCriteria = ['UNSEEN'] const fetchOptions = { bodies: ['HEADER', 'TEXT', ''], - markSeen: false, + markSeen: true, struct: true, } const ignoreImapIDs = [] function main() { - ImapSimple +/* ImapSimple .connect(config) .then((connection) => { $ImapConnection = connection }) .then(ScanUnread) +*/ } + +const ingressMap = {} +socket.on('msgmgr:event', async (eventType, eventData) => { + console.log(eventType, eventData) + switch (eventType) { + case 'status': { + const [msgId, uuid, status] = eventData + ingressMap[ msgId ][2].push(`${ uuid } is ${ status }`) + } break; + case 'read': + ingressMap[ eventData ][2].push('read') + break; + case 'response': { + const [msgId, response] = eventData + if (!!ingressMap[msgId]) { + ingressMap[ msgId ][2].push(`${ uuid } response ${ response }`) + //const [ replyTo, subject, logArray ] = ingressMap[msgId] + let info = await smtpTransporter.sendMail({ + from: `"msg-email--smartpager 👻" <${ config.smtp.user }>`, + to: ingressMap[msgId][ 0 ], + subject: `Response [${ ingressMap[msgId][ 1 ] }] ${ response.toString() }`, + text: `Response: ${ response.toString() }\n${ ingressMap[msgId][ 2 ].join('\n') }`, + inReplyTo: ingressMap[msgId][ 3 ] + }); + + console.log("Message sent: %s", info.messageId, ingressMap[ msgId ]); + } + } break; + } +}) + + async function sendPage(payload) { console.log(payload) - await axios.post(config.pager.url, Object.assign({ ...config.pager.params }, { payload })) + return (await axios.post(config.pager.url, Object.assign({ ...config.pager.params }, { payload }))) } function checkMatch(mail, cmd) { if (!!cmd.subjectContains && !(mail.subject.indexOf(cmd.subjectContains) > -1)) return 0 // subjectContains does not match @@ -40,16 +106,30 @@ async function processMail(mail) { let res = checkMatch(mail, processCommand) if (res) { if (!!processCommand.format && !processCommand.ignore) { + console.log(mail) let payload = processCommand.format payload = payload.replace("[subject]", mail.subject) payload = payload.replace("[from]", mail.from.text) - payload = payload.replace("[fromName]", mail.from.value[0].name || mail.from.value[0].address) - payload = payload.replace("[fromAddress]", mail.from.value[0].address) + payload = payload.replace("[fromName]", mail.from[0].name || mail.from[0].address) + payload = payload.replace("[fromAddress]", mail.from[0].address) sendPage(payload) + .then(result => { + if (!!processCommand.duplexReply) { + ingressMap[ result.data ] = [ + mail.from[0].address, + mail.subject, + [], + mail.messageId + ] + console.log('Duplex Handling Active', result.data, mail.from[0].address) + return + } + }) } } } } +/* function ScanUnread() { return $ImapConnection.openBox('INBOX') .then(() => $ImapConnection.search(searchCriteria, fetchOptions)) @@ -68,6 +148,28 @@ function ScanUnread() { } }) } +*/ +mailListener.on("server:connected", () => { + console.log("imapConnected") +}) +mailListener.on("server:disconnected", () => { + console.log("imapDisconnected") + require('process').exit() +}) +mailListener.on("error", (err) => { + console.log(err) +}) + +mailListener.on("mail", async (mail, seqno, attributes) => { + //if (mail.headers.from == "eBay Kleinanzeigen " && mail.headers.subject == "Aktiviere jetzt dein eBay Kleinanzeigen Konto") { + console.log("emailParsed", mail.headers.subject, mail.headers.to) + processMail(mail) + //await fuckEcho(mail.html, mail.headers.to) + // await registrator.handleMail(mail.html, mail.headers.to) + //} +}) + +mailListener.start() main() @@ -105,4 +207,4 @@ appConfig.post('/restart', (req, res) => { process.exit(1) }) -appConfig.listen(3010) \ No newline at end of file +appConfig.listen(3010, '0.0.0.0' || config.host || '127.0.0.1') diff --git a/package.json b/package.json index 9fea548..a2f7ea5 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,10 @@ "axios": "^0.21.1", "express": "^4.17.1", "imap-simple": "^5.0.0", + "mail-listener2": "^0.3.1", "mailparser": "^3.1.0", - "node-imap": "^0.9.6" + "node-imap": "^0.9.6", + "nodemailer": "^6.4.18", + "socket.io-client": "^4.4.1" } }