Browse Source

Initial: AMQP CloudEvent to email forwarder

main
jochen 1 month ago
commit
6afb915d8a
5 changed files with 134 additions and 0 deletions
  1. +6
    -0
      Dockerfile
  2. +78
    -0
      app.js
  3. +7
    -0
      docker-compose.yml
  4. +34
    -0
      module.yml
  5. +9
    -0
      package.json

+ 6
- 0
Dockerfile View File

@@ -0,0 +1,6 @@
FROM node:22-alpine
WORKDIR /app
COPY package.json ./
RUN npm install --production
COPY app.js ./
CMD ["node", "app.js"]

+ 78
- 0
app.js View File

@@ -0,0 +1,78 @@
const amqp = require("amqplib");
const nodemailer = require("nodemailer");

const {
AMQP_URL,
AMQP_EXCHANGE,
AMQP_QUEUE = "email-forwarder",
SMTP_HOST,
SMTP_PORT = "25",
NOTIFY_TO,
NOTIFY_FROM = "hal@novox.be",
} = process.env;

async function main() {
console.log(`Connecting to AMQP: ${AMQP_URL?.replace(/\/\/.*@/, "//***@")}`);
const conn = await amqp.connect(AMQP_URL);
const ch = await conn.createChannel();

await ch.assertQueue(AMQP_QUEUE, { durable: true });
await ch.bindQueue(AMQP_QUEUE, AMQP_EXCHANGE, "");
console.log(`Bound queue '${AMQP_QUEUE}' to exchange '${AMQP_EXCHANGE}'`);

const transport = nodemailer.createTransport({
host: SMTP_HOST,
port: parseInt(SMTP_PORT),
secure: false,
tls: { rejectUnauthorized: false },
});

console.log(`SMTP: ${SMTP_HOST}:${SMTP_PORT}`);
console.log(`Forwarding to: ${NOTIFY_TO}`);
console.log("Waiting for messages...\n");

ch.consume(AMQP_QUEUE, async (msg) => {
if (!msg) return;

try {
const headers = {};
for (const [k, v] of Object.entries(msg.properties.headers || {})) {
headers[k] = Buffer.isBuffer(v) ? v.toString() : v;
}

const body = JSON.parse(msg.content.toString());
const subjectType = headers.subjecttype || "unknown";
const brandCode = body.brandCode || "unknown";
const ref = body.transactionReference || "unknown";

const subject = `[CloudEvent] ${subjectType} / ${brandCode} / ${ref}`;
const html = `
<h2>CloudEvent received</h2>
<h3>Headers</h3>
<pre>${JSON.stringify(headers, null, 2)}</pre>
<h3>CDM Payload</h3>
<pre>${JSON.stringify(body, null, 2)}</pre>
<hr>
<p><small>From: AH BE Task Connector → ${AMQP_EXCHANGE} → ${AMQP_QUEUE}</small></p>
`;

await transport.sendMail({
from: NOTIFY_FROM,
to: NOTIFY_TO,
subject,
html,
});

console.log(`Forwarded: ${subject} → ${NOTIFY_TO}`);
ch.ack(msg);
} catch (err) {
console.error("Failed to process message:", err.message);
ch.nack(msg, false, true);
}
});
}

main().catch((err) => {
console.error("Fatal:", err);
process.exit(1);
});

+ 7
- 0
docker-compose.yml View File

@@ -0,0 +1,7 @@
services:
amqp-email-forwarder:
image: registry-api.novox.be/novox/amqp-email-forwarder:latest
restart: unless-stopped
env_file: .env
extra_hosts:
- "host.docker.internal:host-gateway"

+ 34
- 0
module.yml View File

@@ -0,0 +1,34 @@
manifest: 2
name: amqp-email-forwarder
version: "1.0.0"
description: "Consumes CloudEvents from AMQP and forwards as email notifications"

service:
container: amqp-email-forwarder

docker:
- image: amqp-email-forwarder
context: .
dockerfile: Dockerfile

env:
AMQP_URL:
default: "amqp://EMAILDELIVERY_T:ke-O8ws9j8EJQCbDmso-MpoB@localhost:5679/EMAILDELIVERY_T"
AMQP_EXCHANGE:
default: "News.TransactionalEmailing.Command"
AMQP_QUEUE:
default: "email-forwarder"
SMTP_HOST:
default: "localhost"
SMTP_PORT:
default: "25"
NOTIFY_TO:
default: "jochen.schoubben@mediahuis.be"
NOTIFY_FROM:
default: "hal@novox.be"

package:
- docker-compose.yml
- Dockerfile
- app.js
- package.json

+ 9
- 0
package.json View File

@@ -0,0 +1,9 @@
{
"name": "amqp-email-forwarder",
"version": "1.0.0",
"private": true,
"dependencies": {
"amqplib": "^0.10.4",
"nodemailer": "^6.9.15"
}
}

Loading…
Cancel
Save