agentleFS
roedyrustamroedyrustam/vibes-plug/skills/email-notification-expert/SKILL.md

email-notification-expert

Skill75 starsChanged 38 days agoMITView on GitHub

Expert guide for transactional email (Resend, Postmark, SES), React Email templates, in-app notifications, and unified communication pipelines / Panduan ahli untuk email transaksional (Resend, Postmark, SES), template React Email, notifikasi in-app, dan pipeline komunikasi terpadu.

  • Reads credentials

The file

We split this skill into the rules it gives an agent

2 rules. About 0 are common, 2 are distinctive, and 0 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Recommendation: Use Resend for most new projects (best DX with React Email).

    line 45
  2. Distinctive:

    iOS Live Activities / Dynamic Island: Update real-time status (orders, deliveries, live events) using ActivityKit.

    line 317

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Email & Notification Expert (2026 Edition)

English | Bahasa Indonesia


<a name="english"></a>

English

Orchestration & Integration

Connects and orchestrates with relevant domain skills like brainstorming, zero-to-prod-orchestrator, and session-memory-manager to ensure cohesive execution.

Description

Production-grade guide for building reliable email delivery systems and unified notification pipelines. Covers Resend, Postmark, AWS SES, React Email / MJML template engines, email deliverability (SPF, DKIM, DMARC), in-app notification systems (bell icon, toast, notification center), webhook-triggered email flows, email queuing with BullMQ/Inngest, and CAN-SPAM/GDPR compliance.

Trigger Conditions

Activate this skill when:

  • Setting up transactional email (welcome, password reset, invoices, team invites).
  • Building email templates with React Email or MJML.
  • Integrating Resend, Postmark, SendGrid, or AWS SES.
  • Implementing in-app notification systems (real-time bell, toast, notification center).
  • Configuring email deliverability (SPF, DKIM, DMARC records).
  • Building email queue systems for high-volume sends.
  • Implementing unsubscribe management and compliance.

Email Provider Selection Guide

ProviderBest ForKey StrengthPricing Model
ResendModern apps, React EmailDeveloper DX, React components as emailPer email (free tier: 3k/mo)
PostmarkTransactional-onlyIndustry-best deliverability, dedicated IPPer email (free tier: 100/mo)
AWS SESHigh volume, cost-sensitiveCheapest at scale ($0.10/1000 emails)Per email
SendGridMarketing + TransactionalFull marketing suite, analyticsTiered plans
PlunkSelf-hostable, open-sourceFull control, no vendor lock-inFree (self-hosted)

Recommendation: Use Resend for most new projects (best DX with React Email). Use Postmark for mission-critical transactional emails. Use AWS SES for high-volume (10k+/day) cost optimization.


1. React Email Templates

// emails/welcome.tsx
import {
  Body, Button, Container, Head, Heading,
  Html, Img, Link, Preview, Section, Text,
} from '@react-email/components';

interface WelcomeEmailProps {
  username: string;
  loginUrl: string;
}

export default function WelcomeEmail({ username, loginUrl }: WelcomeEmailProps) {
  return (
    <Html>
      <Head />
      <Preview>Welcome to our platform, {username}!</Preview>
      <Body style={main}>
        <Container style={container}>
          <Img src="https://yourdomain.com/logo.png" width={48} height={48} alt="Logo" />
          <Heading style={heading}>Welcome, {username}! 🎉</Heading>
          <Text style={text}>
            We're thrilled to have you on board. Your account is ready.
          </Text>
          <Section style={buttonContainer}>
            <Button style={button} href={loginUrl}>
              Get Started
            </Button>
          </Section>
          <Text style={footer}>
            If you didn't create this account, you can safely ignore this email.
          </Text>
        </Container>
      </Body>
    </Html>
  );
}

const main = { backgroundColor: '#f6f9fc', fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' };
const container = { backgroundColor: '#ffffff', margin: '0 auto', padding: '40px 20px', borderRadius: '8px', maxWidth: '560px' };
const heading = { fontSize: '24px', fontWeight: '600' as const, color: '#1a1a1a', margin: '24px 0 16px' };
const text = { fontSize: '16px', lineHeight: '26px', color: '#484848' };
const buttonContainer = { textAlign: 'center' as const, margin: '32px 0' };
const button = { backgroundColor: '#5046e5', borderRadius: '6px', color: '#fff', fontSize: '16px', padding: '12px 24px', textDecoration: 'none' };
const footer = { fontSize: '13px', color: '#999', marginTop: '32px' };

2. Sending Emails with Resend

// lib/email.ts
import { Resend } from 'resend';
import WelcomeEmail from '@/emails/welcome';

const resend = new Resend(process.env.RESEND_API_KEY);

export async function sendWelcomeEmail(to: string, username: string) {
  const { data, error } = await resend.emails.send({
    from: 'Your App <noreply@yourdomain.com>',
    to,
    subject: `Welcome to Our Platform, ${username}!`,
    react: WelcomeEmail({ username, loginUrl: 'https://app.yourdomain.com/login' }),
    // Optional: plain text fallback
    text: `Welcome ${username}! Get started at https://app.yourdomain.com/login`,
    // Optional: tags for analytics
    tags: [
      { name: 'category', value: 'onboarding' },
    ],
  });

  if (error) {
    throw new Error(`Failed to send welcome email: ${error.message}`);
  }

  return data;
}

3. Email Queue for High-Volume

// queues/email-queue.ts
import { Queue, Worker } from 'bullmq';
import { sendEmail } from '@/lib/email';

// Queue definition
export const emailQueue = new Queue('emails', {
  connection: { host: process.env.REDIS_HOST, port: 6379 },
  defaultJobOptions: {
    attempts: 3,
    backoff: { type: 'exponential', delay: 2000 },
    removeOnComplete: { age: 86400 }, // Keep for 24h
    removeOnFail: { age: 604800 },    // Keep failed for 7 days
  },
});

// Worker (separate process)
const emailWorker = new Worker('emails', async (job) => {
  const { type, to, data } = job.data;

  switch (type) {
    case 'welcome':
      await sendWelcomeEmail(to, data.username);
      break;
    case 'password-reset':
      await sendPasswordResetEmail(to, data.resetToken);
      break;
    case 'invoice':
      await sendInvoiceEmail(to, data.invoiceId);
      break;
    default:
      throw new Error(`Unknown email type: ${type}`);
  }
}, {
  connection: { host: process.env.REDIS_HOST, port: 6379 },
  concurrency: 5,  // Process 5 emails at a time
  limiter: { max: 50, duration: 1000 }, // Max 50 emails/second (respect provider limits)
});

// Enqueue email from API route
export async function queueEmail(type: string, to: string, data: Record<string, unknown>) {
  await emailQueue.add(type, { type, to, data });
}

4. Email Deliverability Setup

DNS Records Required

# SPF — Authorize sending servers
TXT  @  "v=spf1 include:_spf.resend.com ~all"

# DKIM — Cryptographic signature
CNAME  resend._domainkey  resend._domainkey.yourdomain.com

# DMARC — Policy for failed authentication
TXT  _dmarc  "v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain.com; pct=100"

# Return-Path (custom bounce domain)
CNAME  bounce  feedback-smtp.us-east-1.amazonses.com

Deliverability Checklist

  • SPF record configured and verified
  • DKIM signing enabled and verified
  • DMARC policy set to at least p=quarantine
  • Custom From domain (not @gmail.com or @resend.dev)
  • List-Unsubscribe header present in all marketing emails
  • Bounce handling configured (remove invalid addresses)
  • Complaint feedback loop registered with major ISPs
  • Email content passes spam filter checks (no ALL CAPS, excessive links)

5. In-App Notification System

// db/schema — Notification table (Drizzle ORM)
import { pgTable, text, timestamp, boolean, uuid } from 'drizzle-orm/pg-core';

export const notifications = pgTable('notifications', {
  id: uuid('id').primaryKey().defaultRandom(),
  userId: uuid('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
  type: text('type').notNull(), // 'info' | 'warning' | 'success' | 'error'
  title: text('title').notNull(),
  message: text('message').notNull(),
  actionUrl: text('action_url'),
  isRead: boolean('is_read').default(false).notNull(),
  createdAt: timestamp('created_at').defaultNow().notNull(),
});

// API: Mark notification as read
export async function markAsRead(notificationId: string, userId: string) {
  await db.update(notifications)
    .set({ isRead: true })
    .where(and(
      eq(notifications.id, notificationId),
      eq(notifications.userId, userId),
    ));
}

// API: Get unread count
export async function getUnreadCount(userId: string): Promise<number> {
  const [result] = await db.select({ count: count() })
    .from(notifications)
    .where(and(
      eq(notifications.userId, userId),
      eq(notifications.isRead, false),
    ));
  return result.count;
}
// components/notification-bell.tsx
'use client';

import { useQuery } from '@tanstack/react-query';
import { Bell } from 'lucide-react';

export function NotificationBell() {
  const { data: unreadCount } = useQuery({
    queryKey: ['notifications', 'unread-count'],
    queryFn: () => fetch('/api/notifications/unread-count').then(r => r.json()),
    refetchInterval: 30_000, // Poll every 30 seconds
  });

  return (
    <button className="notification-bell" aria-label={`${unreadCount ?? 0} unread notifications`}>
      <Bell size={20} />
      {unreadCount > 0 && (
        <span className="notification-badge">{unreadCount > 99 ? '99+' : unreadCount}</span>
      )}
    </button>
  );
}

6. Unsubscribe & Compliance

// Mandatory headers for CAN-SPAM/GDPR compliance
const emailHeaders = {
  'List-Unsubscribe': '<https://app.yourdomain.com/unsubscribe?token=xxx>',
  'List-Unsubscribe-Post': 'List-Unsubscribe=One-Click',
};

// One-click unsubscribe endpoint
export async function POST(request: Request) {
  const { token } = await request.json();
  const decoded = verifyUnsubscribeToken(token);
  await db.update(emailPreferences)
    .set({ unsubscribed: true, unsubscribedAt: new Date() })
    .where(eq(emailPreferences.userId, decoded.userId));
  return new Response('Unsubscribed', { status: 200 });
}

7. Mobile Push Notifications & iOS Live Activities

import * as Notifications from 'expo-notifications';

// Register for push tokens (Expo Push / FCM / APNs)
export async function registerForPushNotificationsAsync() {
  const { status: existingStatus } = await Notifications.getPermissionsAsync();
  let finalStatus = existingStatus;
  if (existingStatus !== 'granted') {
    const { status } = await Notifications.requestPermissionsAsync();
    finalStatus = status;
  }
  if (finalStatus !== 'granted') return null;
  return (await Notifications.getExpoPushTokenAsync()).data;
}
  • Expo Push & FCM: Send batched push notifications with deep links, actions, and custom data payloads.
  • iOS Live Activities / Dynamic Island: Update real-time status (orders, deliveries, live events) using ActivityKit.
  • Push Token Lifecycle: Save push tokens to database associated with userId; handle token rotation and app reinstall events.

Common Pitfalls to Avoid

Anti-PatternProblemCorrect Approach
Sending email synchronously in API routesSlow response times, timeout riskQueue emails with BullMQ/Inngest
Using @gmail.com as senderPoor deliverability, spam filtersUse custom domain with SPF/DKIM
No plain-text fallbackEmails may display incorrectlyAlways include text alongside HTML
Hardcoded email contentCan't update without deploysUse templates with dynamic variables
No unsubscribe linkCAN-SPAM violation, ISP blockingAlways include List-Unsubscribe header
Sending passwords in emailSecurity vulnerabilitySend one-time reset links with expiry

Integration with Other Skills

  • saas-billing — Payment receipt emails, failed payment dunning sequences
  • saas-architect — Team invitation emails, workspace notifications
  • authentication-identity-expert — Password reset emails, email verification, MFA codes
  • mobile-expo-expert — Unified notification strategy (email + push + in-app)
  • async-queue-temporal-expert — Email queue workers with BullMQ/Inngest
  • production-ready-hardener — Email deliverability audit before launch

<a name="bahasa-indonesia"></a>

Bahasa Indonesia

Integrasi Orkestrasi

Terhubung dan mengorkestrasi skill domain yang relevan seperti brainstorming, zero-to-prod-orchestrator, dan session-memory-manager untuk memastikan eksekusi yang kohesif.

Deskripsi

Panduan tingkat produksi untuk membangun sistem pengiriman email yang andal dan pipeline notifikasi terpadu. Mencakup Resend, Postmark, AWS SES, mesin template React Email / MJML, deliverabilitas email (SPF, DKIM, DMARC), sistem notifikasi in-app (bell icon, toast, pusat notifikasi), alur email berbasis webhook, antrean email dengan BullMQ/Inngest, dan kepatuhan CAN-SPAM/GDPR.

Kondisi Pemicu

Aktifkan skill ini ketika:

  • Menyiapkan email transaksional (selamat datang, reset password, invoice, undangan tim).
  • Membangun template email dengan React Email atau MJML.
  • Mengintegrasikan Resend, Postmark, SendGrid, atau AWS SES.
  • Mengimplementasikan sistem notifikasi in-app (bell real-time, toast, pusat notifikasi).
  • Mengonfigurasi deliverabilitas email (SPF, DKIM, DMARC).
  • Membangun sistem antrean email untuk pengiriman volume tinggi.
  • Mengimplementasikan manajemen unsubscribe dan kepatuhan regulasi.

Panduan Pemilihan Provider Email

ProviderTerbaik UntukKekuatan UtamaModel Harga
ResendAplikasi modern, React EmailDX developer terbaik, komponen React sebagai emailPer email (gratis: 3k/bulan)
PostmarkHanya transaksionalDeliverabilitas terbaik di industri, IP dedicatedPer email (gratis: 100/bulan)
AWS SESVolume tinggi, hemat biayaTermurah di skala besar ($0.10/1000 email)Per email
SendGridMarketing + TransaksionalSuite marketing lengkap, analitikPaket bertingkat

Rekomendasi: Gunakan Resend untuk kebanyakan proyek baru (DX terbaik dengan React Email). Gunakan Postmark untuk email transaksional misi-kritis. Gunakan AWS SES untuk optimasi biaya volume tinggi (10k+/hari).

Notifikasi Push Mobile & iOS Live Activities

  • Expo Push & FCM: Kirim notifikasi push masal dengan payload kustom, aksi tombol, dan deep linking ke rute aplikasi (Expo Router).
  • iOS Live Activities: Tampilkan status dinamis secara real-time pada Dynamic Island dan Lock Screen iOS menggunakan ActivityKit.
  • Siklus Hidup Push Token: Simpan token push ke database per userId dan tangani event rotasi token saat instal ulang aplikasi.

Kesalahan Umum yang Harus Dihindari

Anti-PolaMasalahPendekatan yang Benar
Mengirim email secara sinkron di API routeWaktu respons lambat, risiko timeoutAntrean email dengan BullMQ/Inngest
Menggunakan @gmail.com sebagai pengirimDeliverabilitas buruk, filter spamGunakan domain kustom dengan SPF/DKIM
Tidak ada fallback teks biasaEmail mungkin tampil tidak benarSelalu sertakan text di samping HTML
Tidak ada link unsubscribePelanggaran CAN-SPAM, pemblokiran ISPSelalu sertakan header List-Unsubscribe

Integrasi dengan Skill Lain

  • saas-billing — Email kuitansi pembayaran, sekuens dunning gagal bayar
  • saas-architect — Email undangan tim, notifikasi workspace
  • authentication-identity-expert — Email reset password, verifikasi email, kode MFA
  • async-queue-temporal-expert — Worker antrean pengiriman email & push dengan BullMQ/Inngest
  • production-ready-hardener — Audit deliverabilitas email sebelum peluncuran

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.