diff --git a/.gitea/workflows/analytics-mailer.yml b/.gitea/workflows/analytics-mailer.yml index 48bca8b..56cea56 100644 --- a/.gitea/workflows/analytics-mailer.yml +++ b/.gitea/workflows/analytics-mailer.yml @@ -28,9 +28,11 @@ jobs: UMAMI_BASE_URL: ${{ secrets.UMAMI_BASE_URL }} UMAMI_USERNAME: ${{ secrets.UMAMI_USERNAME }} UMAMI_PASSWORD: ${{ secrets.UMAMI_PASSWORD }} - MAILGUN_API_KEY: ${{ secrets.MAILGUN_API_KEY }} - MAILGUN_DOMAIN: ${{ secrets.MAILGUN_DOMAIN }} - MAILGUN_SENDER: ${{ secrets.MAILGUN_SENDER }} + SMTP_HOST: ${{ secrets.SMTP_HOST }} + SMTP_PORT: ${{ secrets.SMTP_PORT }} + SMTP_USER: ${{ secrets.SMTP_USER }} + SMTP_PASS: ${{ secrets.SMTP_PASS }} + SMTP_SENDER: ${{ secrets.SMTP_SENDER }} steps: - name: Checkout uses: actions/checkout@v4 diff --git a/apps/analytics-mailer/package.json b/apps/analytics-mailer/package.json index 5007873..d7115e1 100644 --- a/apps/analytics-mailer/package.json +++ b/apps/analytics-mailer/package.json @@ -12,13 +12,13 @@ "@mintel/mail": "workspace:*", "axios": "^1.7.9", "dotenv": "^16.4.7", - "form-data": "^4.0.1", - "mailgun.js": "^10.3.0" + "nodemailer": "^9.0.3" }, "devDependencies": { "@mintel/eslint-config": "workspace:*", "@mintel/tsconfig": "workspace:*", "@types/node": "^22.19.10", + "@types/nodemailer": "^8.0.1", "tsup": "^8.3.5", "tsx": "^4.19.2", "typescript": "^5.7.2", diff --git a/apps/analytics-mailer/src/index.ts b/apps/analytics-mailer/src/index.ts index e5b8832..c0607b7 100644 --- a/apps/analytics-mailer/src/index.ts +++ b/apps/analytics-mailer/src/index.ts @@ -4,8 +4,7 @@ import axios from "axios"; import { render } from "@mintel/mail"; import { AnalyticsTemplate } from "@mintel/mail"; import { getLast7Days, getThisMonth, getThisYear } from "./utils/time-calculator"; -import Mailgun from "mailgun.js"; -import formData from "form-data"; +import nodemailer from "nodemailer"; import * as dotenv from "dotenv"; dotenv.config(); @@ -15,10 +14,11 @@ const UMAMI_USERNAME = process.env.UMAMI_USERNAME; const UMAMI_PASSWORD = process.env.UMAMI_PASSWORD; const UMAMI_API_KEY = process.env.UMAMI_API_KEY; -const MAILGUN_API_KEY = process.env.MAILGUN_API_KEY; -const MAILGUN_DOMAIN = process.env.MAILGUN_DOMAIN; -const MAILGUN_SENDER = process.env.MAILGUN_SENDER || "reports@mintel.me"; -const MAILGUN_URL = process.env.MAILGUN_URL || "https://api.eu.mailgun.net"; +const SMTP_HOST = process.env.SMTP_HOST || "mail.infra.mintel.me"; +const SMTP_PORT = parseInt(process.env.SMTP_PORT || "587", 10); +const SMTP_USER = process.env.SMTP_USER; +const SMTP_PASS = process.env.SMTP_PASS; +const SMTP_SENDER = process.env.SMTP_SENDER || "reports@mintel.me"; interface ConfigClient { websiteId: string; @@ -116,9 +116,16 @@ async function main() { const httpsAgent = new https.Agent({ rejectUnauthorized: false }); const api = axios.create({ baseURL: `${UMAMI_BASE_URL}/api`, headers, httpsAgent }); - // Setup Mailgun - const mailgun = new Mailgun(formData); - const mg = mailgun.client({ username: "api", key: MAILGUN_API_KEY || "dummy", url: MAILGUN_URL }); + // Setup SMTP Transporter (Nodemailer) + const transporter = nodemailer.createTransport({ + host: SMTP_HOST, + port: SMTP_PORT, + secure: SMTP_PORT === 465, + auth: SMTP_USER && SMTP_PASS ? { + user: SMTP_USER, + pass: SMTP_PASS, + } : undefined, + }); const timeRanges = [getLast7Days(), getThisMonth(), getThisYear()]; @@ -153,12 +160,12 @@ async function main() { await fs.writeFile(debugPath, html); console.log(`[DRY-RUN] Saved HTML preview to ${debugPath}`); } else { - if (!MAILGUN_API_KEY) { - throw new Error("MAILGUN_API_KEY is missing for live run."); + if (!SMTP_HOST) { + throw new Error("SMTP_HOST is missing for live run."); } - await mg.messages.create(MAILGUN_DOMAIN!, { - from: MAILGUN_SENDER, - to: [client.clientEmail], + await transporter.sendMail({ + from: SMTP_SENDER, + to: client.clientEmail, subject, html, }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 840a033..0316d82 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -115,12 +115,9 @@ importers: dotenv: specifier: ^16.4.7 version: 16.6.1 - form-data: - specifier: ^4.0.1 - version: 4.0.5 - mailgun.js: - specifier: ^10.3.0 - version: 10.4.0 + nodemailer: + specifier: ^9.0.3 + version: 9.0.3 devDependencies: '@mintel/eslint-config': specifier: workspace:* @@ -131,6 +128,9 @@ importers: '@types/node': specifier: ^22.19.10 version: 22.19.10 + '@types/nodemailer': + specifier: ^8.0.1 + version: 8.0.1 tsup: specifier: ^8.3.5 version: 8.5.1(@swc/core@1.15.11(@swc/helpers@0.5.18))(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) @@ -3599,6 +3599,9 @@ packages: '@types/node@22.19.10': resolution: {integrity: sha512-tF5VOugLS/EuDlTBijk0MqABfP8UxgYazTLo3uIn3b4yJgg26QRbVYJYsDtHrjdDUIRfP70+VfhTTc+CE1yskw==} + '@types/nodemailer@8.0.1': + resolution: {integrity: sha512-PxpaInm8V1JQDd4j0ds5HfvWQk8JupS1C0Picb96QJsrrRDjBH+DlK7L4ZdNSqNULhiZRQHc40nLVShaGxXAMw==} + '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} @@ -4303,9 +4306,6 @@ packages: bare-url@2.3.2: resolution: {integrity: sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==} - base-64@1.0.0: - resolution: {integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==} - base64-arraybuffer@1.0.2: resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==} engines: {node: '>= 0.6.0'} @@ -6478,10 +6478,6 @@ packages: resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==} engines: {node: '>=12'} - mailgun.js@10.4.0: - resolution: {integrity: sha512-YrdaZEAJwwjXGBTfZTNQ1LM7tmkdUaz2NpZEu7+zULcG4Wrlhd7cWSNZW0bxT3bP48k5N0mZWz8C2f9gc2+Geg==} - engines: {node: '>=18.0.0'} - map-stream@0.1.0: resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==} @@ -6777,6 +6773,10 @@ packages: node-releases@2.0.27: resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + nodemailer@9.0.3: + resolution: {integrity: sha512-n+YP+NKwR5zRWa60k3GiQ6Q3B4KXCoAw40dAKeCtYn020iNN74aWK2liXIC3ZEATeGql7we3tE3t8QwhY0eskw==} + engines: {node: '>=6.0.0'} + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -8368,9 +8368,6 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - url-join@4.0.1: - resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} - use-context-selector@2.0.0: resolution: {integrity: sha512-owfuSmUNd3eNp3J9CdDl0kMgfidV+MkDvHPpvthN5ThqM+ibMccNE0k+Iq7TWC6JPFvGZqanqiGCuQx6DyV24g==} peerDependencies: @@ -11655,6 +11652,10 @@ snapshots: dependencies: undici-types: 6.21.0 + '@types/nodemailer@8.0.1': + dependencies: + '@types/node': 20.19.33 + '@types/parse-json@4.0.2': {} '@types/pg-pool@2.0.7': @@ -12049,7 +12050,7 @@ snapshots: pathe: 2.0.3 sirv: 3.0.2 tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 + tinyrainbow: 3.1.0 vitest: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.33)(@vitest/ui@4.0.18)(happy-dom@20.5.3)(jiti@2.6.1)(jsdom@27.4.0(canvas@3.2.1))(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) optional: true @@ -12465,8 +12466,6 @@ snapshots: dependencies: bare-path: 3.0.0 - base-64@1.0.0: {} - base64-arraybuffer@1.0.2: {} base64-js@0.0.8: {} @@ -14143,7 +14142,7 @@ snapshots: happy-dom@20.5.3: dependencies: - '@types/node': 20.19.33 + '@types/node': 22.19.10 '@types/whatwg-mimetype': 3.0.2 '@types/ws': 8.18.1 entities: 6.0.1 @@ -14950,14 +14949,6 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 - mailgun.js@10.4.0: - dependencies: - axios: 1.13.5 - base-64: 1.0.0 - url-join: 4.0.1 - transitivePeerDependencies: - - debug - map-stream@0.1.0: {} marked@14.0.0: {} @@ -15197,6 +15188,8 @@ snapshots: node-releases@2.0.27: {} + nodemailer@9.0.3: {} + normalize-path@3.0.0: {} normalize-svg-path@1.1.0: @@ -17165,8 +17158,6 @@ snapshots: dependencies: punycode: 2.3.1 - url-join@4.0.1: {} - use-context-selector@2.0.0(react@19.2.4)(scheduler@0.25.0): dependencies: react: 19.2.4