diff --git a/node/send-email-with-keplars/.gitignore b/node/send-email-with-keplars/.gitignore new file mode 100644 index 00000000..713d5006 --- /dev/null +++ b/node/send-email-with-keplars/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +.env diff --git a/node/send-email-with-keplars/README.md b/node/send-email-with-keplars/README.md new file mode 100644 index 00000000..f8a406d0 --- /dev/null +++ b/node/send-email-with-keplars/README.md @@ -0,0 +1,69 @@ +# Send Email with Keplars + +Send transactional emails from your Appwrite Function using the [Keplars](https://keplars.com) priority-queue API with instant, high, async, or bulk delivery. + +## Usage + +### POST / + +Send an email. + +**Request body:** + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `to` | string \| string[] | Yes | Recipient email address(es) | +| `from` | string | Yes | Sender address (must be verified in Keplars) | +| `subject` | string | Yes | Email subject line | +| `body` | string | No | Email body (HTML or plain text). Required if `template_id` is not set. | +| `from_name` | string | No | Sender display name | +| `template_id` | string | No | Keplars template ID. Required if `body` is not set. | +| `params` | object | No | Template variables | + +**Success response:** + +```json +{ + "ok": true, + "data": { + "id": "msg_...", + "status": "queued" + } +} +``` + +**Error response:** + +```json +{ + "ok": false, + "error": "Missing required fields: to, from, subject" +} +``` + +## Configuration + +| Variable | Description | Required | +| --- | --- | --- | +| `KEPLARS_API_KEY` | Your Keplars API key (`kms_...`) | Yes | + +## Deployment + +1. Create a new Appwrite Function +2. Add the environment variables above +3. Deploy the function + +**Example request:** + +```bash +curl -X POST https://[REGION].appwrite.io/v1/functions/[FUNCTION_ID]/executions \ + -H "X-Appwrite-Project: [PROJECT_ID]" \ + -H "Content-Type: application/json" \ + -d '{ + "to": "user@example.com", + "from": "hello@yourdomain.com", + "subject": "Welcome!", + "body": "
Thanks for signing up.
" + }' +``` + diff --git a/node/send-email-with-keplars/env.d.ts b/node/send-email-with-keplars/env.d.ts new file mode 100644 index 00000000..6b52a94c --- /dev/null +++ b/node/send-email-with-keplars/env.d.ts @@ -0,0 +1,9 @@ +declare global { + namespace NodeJS { + interface ProcessEnv { + KEPLARS_API_KEY: string; + } + } +} + +export {}; diff --git a/node/send-email-with-keplars/package.json b/node/send-email-with-keplars/package.json new file mode 100644 index 00000000..944dfb86 --- /dev/null +++ b/node/send-email-with-keplars/package.json @@ -0,0 +1,13 @@ +{ + "name": "send-email-with-keplars", + "version": "1.0.0", + "description": "Send transactional emails using the Keplars priority-queue API.", + "main": "src/main.js", + "type": "module", + "scripts": { + "format": "prettier --write ." + }, + "devDependencies": { + "prettier": "^3.2.5" + } +} diff --git a/node/send-email-with-keplars/src/main.js b/node/send-email-with-keplars/src/main.js new file mode 100644 index 00000000..17ff6cb0 --- /dev/null +++ b/node/send-email-with-keplars/src/main.js @@ -0,0 +1,71 @@ +import { throwIfMissing } from './utils.js'; + +const ENDPOINT = 'https://api.keplars.com/api/v1/send-email/async'; + +export default async ({ req, res, log, error }) => { + throwIfMissing(process.env, ['KEPLARS_API_KEY']); + + if (req.method !== 'POST') { + return res.json({ ok: false, error: 'Method not allowed' }, 405); + } + + const { to, from, from_name, subject, body, template_id, params } = + req.body ?? {}; + + if (!to || !from || !subject) { + return res.json( + { ok: false, error: 'Missing required fields: to, from, subject' }, + 400 + ); + } + + if (!body && !template_id) { + return res.json( + { + ok: false, + error: 'Either body or template_id must be provided', + }, + 400 + ); + } + + const payload = { + to: Array.isArray(to) ? to : [to], + from, + subject, + }; + + if (from_name) payload.from_name = from_name; + if (body) payload.body = body; + if (template_id) payload.template_id = template_id; + if (params && typeof params === 'object') payload.params = params; + + try { + const response = await fetch(ENDPOINT, { + method: 'POST', + headers: { + Authorization: `Bearer ${process.env.KEPLARS_API_KEY}`, + 'Content-Type': 'application/json', + 'User-Agent': 'keplars-appwrite/1.0.0', + }, + body: JSON.stringify(payload), + }); + + const data = await response.json(); + + if (!response.ok) { + const message = + typeof data?.message === 'string' + ? data.message + : `Keplars API error: ${response.status}`; + error(message); + return res.json({ ok: false, error: message }, response.status); + } + + log(`Email sent to ${Array.isArray(to) ? to.join(', ') : to}`); + return res.json({ ok: true, data }); + } catch (err) { + error(err.message); + return res.json({ ok: false, error: 'Failed to send email' }, 500); + } +}; diff --git a/node/send-email-with-keplars/src/utils.js b/node/send-email-with-keplars/src/utils.js new file mode 100644 index 00000000..c26f9078 --- /dev/null +++ b/node/send-email-with-keplars/src/utils.js @@ -0,0 +1,11 @@ +/** + * @param {Record