ddw-mail-js
v1.0.6
Published
JavaScript client for Direct Digital Mailer
Readme
DDW Mail JS - Direct Digital Mailer JavaScript Client
A lightweight, type-safe JavaScript client for sending emails through the Direct Digital Mailer service. Supports both CommonJS and ES modules with full TypeScript support.
Table of Contents
- Installation
- Quick Start
- Getting Your API Key
- Configuration
- Usage
- API Reference
- Type Definitions
- Examples
- Troubleshooting
- Best Practices
Installation
npm install ddw-mail-jsOr with yarn:
yarn add ddw-mail-jsOr with pnpm:
pnpm add ddw-mail-jsQuick Start
import DirectDigitalMailer from "ddw-mail-js";
// Initialize with your API key
DirectDigitalMailer.init("your-api-key");
// Send an email
const response = await DirectDigitalMailer.send(
"service-id",
"template-id",
["[email protected]"],
{ name: "John", subject: "Welcome" }
);
console.log("Email sent:", response.status);Getting Your API Key
⚠️ CRITICAL: Account Setup Required
Before you can use this package, you must create an account and retrieve your API key:
- Visit the Dashboard: Go to https://mailer.directdigitalworld.com
- Create an Account: Sign up with your email and password
- Navigate to Profile Settings:
- Log in to your account
- Click on your profile icon (top right corner)
- Select "Settings" or "Profile Settings"
- Copy Your API Key:
- Look for the "API Key" section
- Click the copy button to copy your API key
- Keep this key secure - treat it like a password
Secure API Key Management
Never hardcode your API key in source code. Use environment variables:
// ✅ GOOD - Using environment variables
const apiKey = process.env.DDW_MAIL_API_KEY;
DirectDigitalMailer.init(apiKey);
// ❌ BAD - Never do this
DirectDigitalMailer.init("sk_live_abcd1234...");For Browser Applications:
For client-side applications, consider using a backend proxy instead of exposing your API key:
// Frontend - Call your backend endpoint
const response = await fetch("/api/send-email", {
method: "POST",
body: JSON.stringify({
serviceId: "service-123",
templateId: "template-456",
recipients: ["[email protected]"],
variables: { name: "John" },
}),
});
// Backend (Node.js) - Keeps API key secure
import DirectDigitalMailer from "ddw-mail-js";
DirectDigitalMailer.init(process.env.DDW_MAIL_API_KEY);
app.post("/api/send-email", async (req, res) => {
try {
const result = await DirectDigitalMailer.send(
req.body.serviceId,
req.body.templateId,
req.body.recipients,
req.body.variables
);
res.json(result);
} catch (error) {
res.status(500).json({ error: error.message });
}
});Configuration
Initialization
import DirectDigitalMailer from "ddw-mail-js";
// Initialize with API key
DirectDigitalMailer.init("your-api-key-from-profile-settings");Environment-Based Configuration
// Node.js with .env file
import dotenv from "dotenv";
dotenv.config();
const apiKey = process.env.DDW_MAIL_API_KEY;
if (!apiKey) {
throw new Error("DDW_MAIL_API_KEY environment variable is not set");
}
DirectDigitalMailer.init(apiKey);Usage
Initializing the Client
Before calling any send methods, you must initialize the client with your API key:
DirectDigitalMailer.init("your-api-key");If you don't initialize first, you'll get an error:
Error: DirectDigitalMailer is not initialized. Call init() first.Sending Emails
Basic Email Send
const response = await DirectDigitalMailer.send(
"service-123", // serviceId
"template-456", // templateId
["[email protected]"], // recipients array
{
// variables (optional)
name: "John",
subject: "Welcome to our service",
confirmationLink: "https://example.com/confirm?token=abc123",
}
);
console.log("Status:", response.status);
console.log("Response:", response.text);Multiple Recipients
const recipients = [
"[email protected]",
"[email protected]",
"[email protected]",
];
const response = await DirectDigitalMailer.send(
"service-id",
"template-id",
recipients,
{ subject: "Bulk email" }
);With Template Variables
const response = await DirectDigitalMailer.send(
"service-id",
"welcome-template",
["[email protected]"],
{
firstName: "Jane",
lastName: "Doe",
activationLink: "https://example.com/activate?token=xyz",
expiresIn: "24 hours",
}
);Sending with HTML Forms
The client can automatically extract form data and send it as email variables:
HTML Form
<form id="contactForm">
<input type="text" name="name" placeholder="Your name" required />
<input type="email" name="email" placeholder="Your email" required />
<textarea name="message" placeholder="Your message" required></textarea>
<button type="submit">Send</button>
</form>JavaScript
document.getElementById("contactForm").addEventListener("submit", async (e) => {
e.preventDefault();
try {
const response = await DirectDigitalMailer.sendForm(
"service-id",
"contact-template",
["[email protected]"],
"contactForm" // Form ID
);
console.log("Email sent successfully:", response.status);
alert("Message sent!");
} catch (error) {
console.error("Failed to send email:", error);
alert("Failed to send message. Please try again.");
}
});Using Form Element Reference
const form = document.querySelector("form");
const response = await DirectDigitalMailer.sendForm(
"service-id",
"template-id",
["[email protected]"],
form // Pass the form element directly
);API Reference
init(apiKey: string): void
Initializes the DirectDigitalMailer client with your API key.
Parameters:
apiKey(string, required): Your API key from the dashboard profile settings
Throws:
- Error if initialization fails
Example:
DirectDigitalMailer.init(process.env.DDW_MAIL_API_KEY);send(serviceId: string, templateId: string, recipients: string[], variables?: Record<string, any>): Promise<SendResponse>
Sends an email using a template.
Parameters:
serviceId(string, required): Your service ID from the dashboardtemplateId(string, required): The email template IDrecipients(string[], required): Array of recipient email addressesvariables(object, optional): Template variables to populate the email
Returns:
Promise<SendResponse>: Response object with status and content
Throws:
- Error if client is not initialized
- Error if API request fails
Example:
const response = await DirectDigitalMailer.send(
"service-123",
"template-456",
["[email protected]"],
{ name: "John", orderNumber: "12345" }
);sendForm(serviceId: string, templateId: string, recipients: string[], form: HTMLFormElement | string): Promise<SendResponse>
Sends an email with form data as variables.
Parameters:
serviceId(string, required): Your service ID from the dashboardtemplateId(string, required): The email template IDrecipients(string[], required): Array of recipient email addressesform(HTMLFormElement | string, required): Form element or form ID
Returns:
Promise<SendResponse>: Response object with status and content
Throws:
- Error if client is not initialized
- Error if form is not found
- Error if API request fails
Example:
const response = await DirectDigitalMailer.sendForm(
"service-id",
"template-id",
["[email protected]"],
"contactForm"
);Type Definitions
SendResponse
interface SendResponse {
status: number; // HTTP status code
text: string; // Response body as text
json?: () => Promise<any>; // Parse response as JSON
}SendOptions
interface SendOptions {
serviceId: string;
templateId: string;
variables?: Record<string, any>;
userId?: string;
recipients?: string[];
accessToken?: string;
}DirectDigitalMailerAPI
interface DirectDigitalMailerAPI {
init: (apiKey: string) => void;
send: (
serviceId: string,
templateId: string,
recipients: string[],
variables?: Record<string, any>
) => Promise<SendResponse>;
sendForm: (
serviceId: string,
templateId: string,
recipients: string[],
form: HTMLFormElement | string
) => Promise<SendResponse>;
}Examples
React Component Example
import { useState } from "react";
import DirectDigitalMailer from "ddw-mail-js";
export function NewsletterSignup() {
const [email, setEmail] = useState("");
const [status, setStatus] = useState<
"idle" | "loading" | "success" | "error"
>("idle");
const [message, setMessage] = useState("");
// Initialize once on component mount
React.useEffect(() => {
DirectDigitalMailer.init(process.env.REACT_APP_DDW_MAIL_API_KEY);
}, []);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setStatus("loading");
try {
const response = await DirectDigitalMailer.send(
"newsletter-service",
"welcome-email",
[email],
{
email,
timestamp: new Date().toISOString(),
}
);
setStatus("success");
setMessage("Welcome email sent! Check your inbox.");
setEmail("");
} catch (error) {
setStatus("error");
setMessage(
`Error: ${error instanceof Error ? error.message : "Unknown error"}`
);
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Enter your email"
required
disabled={status === "loading"}
/>
<button type="submit" disabled={status === "loading"}>
{status === "loading" ? "Signing up..." : "Sign Up"}
</button>
{message && <p className={status}>{message}</p>}
</form>
);
}Node.js Express Server Example
import express from "express";
import DirectDigitalMailer from "ddw-mail-js";
import dotenv from "dotenv";
dotenv.config();
const app = express();
app.use(express.json());
// Initialize on server startup
DirectDigitalMailer.init(process.env.DDW_MAIL_API_KEY);
// Send welcome email
app.post("/api/users/register", async (req, res) => {
try {
const { email, name } = req.body;
// Validate input
if (!email || !name) {
return res.status(400).json({ error: "Email and name are required" });
}
// Send welcome email
const response = await DirectDigitalMailer.send(
"user-service",
"registration-welcome",
[email],
{
name,
email,
activationLink: `https://example.com/activate?email=${encodeURIComponent(
email
)}`,
}
);
res.json({
success: true,
message: "Registration email sent",
status: response.status,
});
} catch (error) {
console.error("Registration email failed:", error);
res.status(500).json({
error: "Failed to send registration email",
details: error instanceof Error ? error.message : "Unknown error",
});
}
});
// Send password reset email
app.post("/api/password-reset", async (req, res) => {
try {
const { email, resetToken } = req.body;
const response = await DirectDigitalMailer.send(
"user-service",
"password-reset",
[email],
{
email,
resetLink: `https://example.com/reset?token=${resetToken}`,
expiresIn: "1 hour",
}
);
res.json({ success: true, status: response.status });
} catch (error) {
res.status(500).json({ error: "Failed to send reset email" });
}
});
app.listen(3000, () => {
console.log("Server running on port 3000");
console.log("DDW Mail JS initialized");
});Svelte Example
<script lang="ts">
import DirectDigitalMailer from 'ddw-mail-js';
import { onMount } from 'svelte';
let email = '';
let loading = false;
let message = '';
let isSuccess = false;
onMount(() => {
DirectDigitalMailer.init(import.meta.env.VITE_DDW_MAIL_API_KEY);
});
async function handleSubscribe() {
if (!email) return;
loading = true;
message = '';
try {
await DirectDigitalMailer.send(
'newsletter',
'subscription',
[email],
{ email }
);
isSuccess = true;
message = 'Subscription confirmed! Check your email.';
email = '';
} catch (error) {
isSuccess = false;
message = `Error: ${error instanceof Error ? error.message : 'Failed to subscribe'}`;
} finally {
loading = false;
}
}
</script>
<div>
<input
type="email"
bind:value={email}
placeholder="Enter your email"
disabled={loading}
/>
<button on:click={handleSubscribe} disabled={loading || !email}>
{loading ? 'Subscribing...' : 'Subscribe'}
</button>
{#if message}
<p class={isSuccess ? 'success' : 'error'}>{message}</p>
{/if}
</div>
<style>
.success {
color: green;
}
.error {
color: red;
}
</style>Troubleshooting
"DirectDigitalMailer is not initialized. Call init() first."
Problem: You're trying to send an email before initializing the client.
Solution: Call DirectDigitalMailer.init(apiKey) before any send() or sendForm() calls.
// ❌ Wrong
DirectDigitalMailer.send("service-id", "template-id", ["[email protected]"]);
// ✅ Correct
DirectDigitalMailer.init("your-api-key");
DirectDigitalMailer.send("service-id", "template-id", ["[email protected]"]);"Form with ID 'xyz' not found"
Problem: The form ID you passed doesn't exist in the DOM.
Solution: Verify the form ID matches exactly and exists in your HTML.
// ❌ Wrong - Form doesn't exist or ID doesn't match
DirectDigitalMailer.sendForm('service-id', 'template-id', ['[email protected]'], 'contactForm');
// ✅ Correct - Verify form exists
<form id="contactForm">
<!-- form fields -->
</form>
// Then use it
DirectDigitalMailer.sendForm('service-id', 'template-id', ['[email protected]'], 'contactForm');"API request failed with status 401"
Problem: Your API key is invalid, expired, or not properly set.
Solution:
- Verify your API key is correct from the dashboard
- Check if the API key has been revoked
- Make sure you're using the correct environment variable
// Check if API key is loaded
console.log("API Key exists:", !!process.env.DDW_MAIL_API_KEY);
DirectDigitalMailer.init(process.env.DDW_MAIL_API_KEY);"API request failed with status 400"
Problem: Invalid service ID, template ID, or malformed variables.
Solution:
- Verify
serviceIdandtemplateIdare correct - Check template variables match the template requirements
- Ensure recipient emails are valid
// Validate before sending
if (!serviceId || !templateId) {
throw new Error("serviceId and templateId are required");
}
if (!recipients.every((email) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email))) {
throw new Error("Invalid email addresses in recipients");
}
const response = await DirectDigitalMailer.send(
serviceId,
templateId,
recipients,
variables
);"CORS error in browser"
Problem: Sending emails directly from the browser is blocked by CORS.
Solution: Use a backend proxy instead of calling the API from the browser.
// ❌ Don't do this in browser
DirectDigitalMailer.init('api-key'); // Never expose API key!
DirectDigitalMailer.send(...);
// ✅ Do this instead
// Frontend
const response = await fetch('/api/send-email', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ serviceId, templateId, recipients, variables })
});
// Backend keeps API key secureNetwork Timeouts
Problem: API requests are timing out.
Solution:
- Check your internet connection
- Verify the API endpoint is accessible (https://mailer.directdigitalworld.com)
- Retry with exponential backoff
async function sendWithRetry(
serviceId: string,
templateId: string,
recipients: string[],
variables: Record<string, any>,
maxRetries = 3
) {
for (let i = 0; i < maxRetries; i++) {
try {
return await DirectDigitalMailer.send(
serviceId,
templateId,
recipients,
variables
);
} catch (error) {
if (i === maxRetries - 1) throw error;
// Exponential backoff: 1s, 2s, 4s
await new Promise((resolve) =>
setTimeout(resolve, Math.pow(2, i) * 1000)
);
}
}
}Best Practices
1. Always Initialize Early
Initialize the client as soon as possible in your application lifecycle:
// App.tsx (React)
useEffect(() => {
DirectDigitalMailer.init(process.env.REACT_APP_DDW_MAIL_API_KEY);
}, []);
// main.ts (Vue)
app.config.globalProperties.$init = DirectDigitalMailer.init;
DirectDigitalMailer.init(import.meta.env.VITE_DDW_MAIL_API_KEY);
// app.ts (Svelte)
onMount(() => {
DirectDigitalMailer.init(import.meta.env.VITE_DDW_MAIL_API_KEY);
});2. Protect Your API Key
- Use environment variables, never hardcode
- Don't commit
.envfiles to version control - Rotate your API key regularly from the dashboard
- Use different keys for different environments
3. Use Backend Proxies for Client-Side Apps
Never expose your API key in browser code:
// ❌ Never do this
const apiKey = "sk_live_xyz..."; // Browser JavaScript
DirectDigitalMailer.init(apiKey);
// ✅ Always do this
// Frontend: Call your backend
// Backend: Keep API key secure in environment variables4. Validate Input Data
Always validate before sending:
function validateAndSend(
serviceId: string,
templateId: string,
recipients: string[],
variables?: Record<string, any>
) {
// Validate service and template IDs
if (!serviceId || typeof serviceId !== "string") {
throw new Error("Invalid serviceId");
}
if (!templateId || typeof templateId !== "string") {
throw new Error("Invalid templateId");
}
// Validate recipients
if (!Array.isArray(recipients) || recipients.length === 0) {
throw new Error("Recipients must be a non-empty array");
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!recipients.every((email) => emailRegex.test(email))) {
throw new Error("Invalid email address in recipients");
}
// Send the email
return DirectDigitalMailer.send(serviceId, templateId, recipients, variables);
}5. Handle Errors Gracefully
Always catch and handle errors:
try {
const response = await DirectDigitalMailer.send(
"service-id",
"template-id",
["[email protected]"],
variables
);
console.log("Email sent successfully");
} catch (error) {
console.error("Failed to send email:", error);
// Show user-friendly error message
// Log error for debugging
// Retry with exponential backoff if appropriate
}6. Log Important Information
Keep logs for debugging and monitoring:
async function sendEmailWithLogging(
serviceId: string,
templateId: string,
recipients: string[],
variables: Record<string, any>
) {
const startTime = Date.now();
console.log("Sending email...", {
serviceId,
templateId,
recipientCount: recipients.length,
timestamp: new Date().toISOString(),
});
try {
const response = await DirectDigitalMailer.send(
serviceId,
templateId,
recipients,
variables
);
const duration = Date.now() - startTime;
console.log("Email sent successfully", {
status: response.status,
duration: `${duration}ms`,
timestamp: new Date().toISOString(),
});
return response;
} catch (error) {
const duration = Date.now() - startTime;
console.error("Email send failed", {
error: error instanceof Error ? error.message : "Unknown error",
duration: `${duration}ms`,
timestamp: new Date().toISOString(),
});
throw error;
}
}7. Use TypeScript for Type Safety
Leverage the included TypeScript types:
import DirectDigitalMailer, {
SendResponse,
SendOptions,
DirectDigitalMailerAPI,
} from "ddw-mail-js";
// Use types for better IDE support and type checking
const sendEmail = async (options: SendOptions): Promise<SendResponse> => {
return DirectDigitalMailer.send(
options.serviceId,
options.templateId,
options.recipients || [],
options.variables
);
};8. Test Before Production
Always test in development first:
// Use test service/template IDs in development
const config = {
development: {
serviceId: "test-service",
templateId: "test-template",
},
production: {
serviceId: "prod-service",
templateId: "prod-template",
},
};
const env = process.env.NODE_ENV || "development";
const { serviceId, templateId } = config[env];Support
For issues, questions, or feature requests, please visit the dashboard at https://mailer.directdigitalworld.com or contact support.
License
MIT
Version: 1.0.6
Last Updated: December 2025
