Sending entire message to webhook #3523
|
What would be the most efficient way to send the entire message, i.e. EML "file", to a webhook in a queue plugin? So far I'm struggling to find out how to connect Edit: Reading a few plugins and finding out that Haraka plugins seem to use Axios, I gave that library a shot: const axios = require('axios');
const response = await axios.post(this.cfg.main.url, connection?.transaction.message_stream, {
…
});which works without any issues as far as I can see. I cannot tell whether this is the best way to do it though. |
Answered by
dspangenberg
Mar 26, 2026
Replies: 2 comments 10 replies
|
Hi, I get it working with the following code: const axios = require('axios');
const simpleParser = require('mailparser').simpleParser;
const stringify = require ('string.ify')
exports.register = function() {
this.loginfo('dropbox plugin registered');
};
exports.hook_data = function (next, connection) {
return next();
};
exports.hook_data_post = function (next, connection) {
const plugin = this;
plugin.loginfo('hook_data_post called');
if (!connection.transaction.message_stream) {
plugin.logerror('No message_stream available');
return next();
}
plugin.loginfo('message_stream type: ' + typeof connection.transaction.message_stream);
plugin.loginfo('message_stream readable: ' + connection.transaction.message_stream.readable);
simpleParser(connection.transaction.message_stream, (err, mail) => {
if (err) {
plugin.logerror('simpleParser error: ' + err);
return next();
}
plugin.loginfo('simpleParser completed');
plugin.loginfo('E-Mail: ' + stringify(mail));
axios.post('URL', {
payload: mail
})
plugin.loginfo('Processed E-Mail: ' + stringify(_email));
next();
});
}; |
2 replies
Answer selected by
msimerson
|
With (somewhat) recent supply chain issues and Axios being compromised, I opted for using Undici from NodeJS. 'use strict'
const fs = require('node:fs');
const { fetch, Agent } = require('undici');
exports.register = function () {
this.load_config();
this.register_hook('queue', 'hook_queue');
};
exports.load_config = function () {
this.cfg = this.config.get('webhook_forward.ini', {
booleans: [
'-allow_self_signed',
],
},
() => {
this.load_config();
});
};
exports.hook_queue = async function (next, connection) {
const transaction = connection?.transaction;
if (!transaction) {
return next();
}
const writeToFile = (code, message) => {
const file = `${this.cfg.main.failed_requests_dir}/mail_${transaction.uuid}.eml`;
const stream = fs.createWriteStream(file);
stream.once('close', () => next(code, message));
transaction.message_stream.pipe(stream);
};
try {
this.lognotice(`Sending to ${this.cfg.main.url}`);
const response = await fetch(this.cfg.main.url, {
method: 'POST',
duplex: 'half',
body: transaction.message_stream,
agent: new Agent({
rejectUnauthorized: this.cfg.main.allow_self_signed,
}),
headers: {
'Content-Type': 'message/rfc822',
'User-Agent': 'haraka',
'Authorization': `Bearer ${this.cfg.main.secret}`,
'Message-Type': 'queue',
'Message-ID': transaction.uuid,
'Message-From': transaction.mail_from.toString(),
},
});
if (!response.ok || response.status !== 202) {
this.logerror(`Invalid response status ${response.status}`);
return next(DENYSOFT, 'Processing failed');
}
// consume body to be sure the request is done in the app
await response.text();
return next(OK);
} catch (e) {
this.logerror(`Webhook processing failed with: ${e.message}`);
writeToFile(DENYSOFT, 'Unexpected internal error');
}
};This is just a simple implementation to forward to a webhook with very minimal requirements. |
8 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi,
I get it working with the following code: