Examples & Recipes
Copy working Lumail TypeScript SDK and CLI recipes for signup onboarding, bulk imports with rate limit retries, purchase tracking, and scheduled sends.
Practical examples of what you can build with Lumail's AI integrations.
Automated Onboarding Sequence
When a user signs up, automatically add them to Lumail with the right tags and trigger a welcome workflow:
import { Lumail } from "lumail";
const lumail = new Lumail({ apiKey: process.env.LUMAIL_API_KEY! });
export async function onUserSignup(user: {
email: string;
name: string;
plan: string;
}) {
await lumail.subscribers.create({
email: user.email,
name: user.name,
tags: [user.plan, "onboarding", "new-signup"],
fields: {
plan: user.plan,
signupDate: new Date().toISOString(),
},
triggerWorkflows: true,
});
}Bulk Import with Progress
Import subscribers from a CSV or database with error handling:
import { Lumail, LumailRateLimitError } from "lumail";
const lumail = new Lumail({ apiKey: process.env.LUMAIL_API_KEY! });
async function bulkImport(contacts: { email: string; name: string }[]) {
const results = { success: 0, failed: 0, errors: [] as string[] };
for (const contact of contacts) {
try {
await lumail.subscribers.create({
email: contact.email,
name: contact.name,
tags: ["import-2025"],
});
results.success++;
} catch (error) {
if (error instanceof LumailRateLimitError) {
await new Promise((r) => setTimeout(r, error.retryAfter ?? 2000));
// Retry this one
await lumail.subscribers.create({
email: contact.email,
name: contact.name,
tags: ["import-2025"],
});
results.success++;
} else {
results.failed++;
results.errors.push(`${contact.email}: ${(error as Error).message}`);
}
}
}
return results;
}E-commerce Order Tracking
Track purchases and tag customers by spending tier:
async function trackPurchase(email: string, amount: number, product: string) {
// Track the payment event
await lumail.events.create({
eventType: "SUBSCRIBER_PAYMENT",
subscriber: email,
data: { amount, product, currency: "USD" },
});
// Tag by spending tier
const tierTag =
amount >= 100 ? "high-value" : amount >= 50 ? "mid-value" : "starter";
await lumail.subscribers.addTags(email, [tierTag, "customer"]);
}Scheduled Campaign Pipeline
Create and schedule campaigns programmatically:
async function scheduleWeeklyNewsletter(content: string) {
// Create campaign
const { campaignId } = await lumail.campaigns.create({
name: `Newsletter ${new Date().toISOString().slice(0, 10)}`,
subject: "This Week at Acme",
contentType: "MARKDOWN",
});
// Schedule for next Tuesday 9am UTC
const nextTuesday = getNextDayOfWeek(2); // 0=Sun, 2=Tue
nextTuesday.setHours(9, 0, 0, 0);
await lumail.campaigns.send(campaignId, {
scheduledAt: nextTuesday.toISOString(),
timezone: "UTC",
});
return campaignId;
}
function getNextDayOfWeek(day: number): Date {
const now = new Date();
const diff = (day - now.getDay() + 7) % 7 || 7;
return new Date(now.getTime() + diff * 86400000);
}CLI: Quick One-liners
# Export all VIP subscribers as CSV
lumail tools run list_subscribers \
--params '{"tag": "vip", "limit": 1000}' \
--format csv > vip-subscribers.csv
# Send a test email
lumail emails send \
--to [email protected] \
--from [email protected] \
--subject "Test" \
--markdown "This is a test email from the CLI"Test-mode recipients. Fixture addresses such as
[email protected]never send real email. See Test-mode recipients.
# Tag all subscribers from a list
cat emails.txt | while read email; do
lumail subscribers add-tags "$email" --tags "campaign-march"
doneClaude Code: Natural Language
With MCP connected, just tell Claude what to do:
"Import the contacts from contacts.csv into Lumail,
tag them as 'webinar-attendees', and create a
follow-up campaign with the subject 'Thanks for attending'""Show me which campaigns had the best open rate
this month and create a similar one for next week""Unsubscribe all subscribers who haven't opened
an email in the last 90 days"