diff --git a/README.md b/README.md index 7081727..fa6b2ae 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,46 @@ # haraka-plugin-resque +# NOTE +This plugin uses the global `fetch` function, which only available with nodejs >= 18. As of the writing of this plugin, nodejs 16 has already reached its end-of-life anyway. + +# Ideal Setup +You're a SASS Provider (such as form submission like Wufoo) requiring to send email on-behalf-of client. + +SMTP -> Haraka -> API -> REAL SMTP using a different email sends on behalf of + +1. Using an existing software, you want to use SMTP to send email; so we setup Haraka with auth flat_file plugin allowing you to login. + +```sh +echo "tls +auth/flat_file" > config/plugins +vi config/auth_flat_file.ini +``` +Ref: https://haraka.github.io/plugins/auth/flat_file + +2. This plugin pushes your email to the API. + +```sh +cd /path/to/local/haraka +npm install haraka-plugin-resque +echo "resque" >> config/plugins +service haraka restart +``` + +3. This plugin blackhole all outgoing email. + +Edit `outbound.ini` https://haraka.github.io/core/Outbound#outboundini +And disable outbound with: +``` +; see http://haraka.github.io/manual/Outbound.html +; +; disabled (default: false) +disabled=true +``` + +More info: https://dzone.com/articles/creating-your-own-e-mail-service-with-haraka-postg +https://github.com/haraka/Haraka/issues/20 + # Add your content here ## INSTALL diff --git a/config/resque.ini b/config/resque.ini index 2a92888..6f7087b 100644 --- a/config/resque.ini +++ b/config/resque.ini @@ -1,2 +1,11 @@ [main] +# this is to enable the plugin +enabled=true + +# URL to send the email data to +# Ex. https://example.com/captureEmail.php +url=https://example.com/captureEmail.php + +# the api key +apikey=31be88ea-3412-4132-a529-07d01313391a diff --git a/index.js b/index.js index 662e7d3..3f2353f 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,16 @@ 'use strict' +function streamToString (stream) { + const chunks = []; + return new Promise((resolve, reject) => { + stream.on('data', (chunk) => chunks.push(Buffer.from(chunk))); + stream.on('error', (err) => reject(err)); + stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8'))); + }) +} + exports.register = function () { + this.logdebug("initializing reque"); this.load_resque_ini() // register hooks here. More info at https://haraka.github.io/core/Plugins/ @@ -18,6 +28,63 @@ exports.load_resque_ini = function () { ] }, function () { - plugin.load_example_ini() + // plugin.load_example_ini() + this.logdebug("config loaded"); }) } + +// Hook to add to queue +exports.hook_queue = async function (next, connection) { + const plugin = this + const transaction = connection.transaction + const url = plugin.cfg.main.url + let eml = ''; + + try { + eml = await streamToString(transaction.message_stream) + } + catch (err) { + return next(DENYSOFT, '458 – Unable to queue messages for node; ' . err); + } + + // https://oxylabs.io/blog/nodejs-fetch-api + const data = { + eml + } + const postData = JSON.stringify(data) + const customHeaders = { + "accept": "application/json", + "Content-Type": "application/json", + "x-api-key": plugin.cfg.main.apikey + // fyi, NO need for content length + } + + const options = { + method: "POST", + headers: customHeaders, + body: postData + } + + try { + const response = await fetch(url, options) + const text = await response.text(); + + // network error in the 4xx–5xx range + // ok is in the range of 200-299 + if (! response.ok) { + plugin.logdebug(text); + throw new Error(`${response.status} ${response.statusText}`); + } + + } + catch (err) { + plugin.logdebug(err); + + // blackhole this message as deny + return next(DENYSOFT, '458 – Unable to queue messages for node resque'); + } + + // successful POST, send next(OK) implies we blackhole this message from further processing. + return next(OK, "Your message has been resqued.") +} +