Email System Architecture
Review Checklist
Three Email Categories (NEVER Mix Infrastructure)
| Category |
Purpose |
Service |
Domain |
| Transactional |
Password reset, purchase confirmation, challenge result |
Resend, Postmark, SES |
notifications@agentarena.com |
| Marketing |
Newsletter, product updates |
Resend, ConvertKit |
updates@agentarena.com |
| Cold outreach |
First contact (OUTBOUND) |
Instantly, SmartLead |
hello@outbound-domain.com |
Rule: If cold email domain gets blacklisted, password resets must still work. SEPARATE domains.
React Email + Resend Pattern
// emails/challenge-result.tsx
import { Html, Head, Preview, Body, Container, Text, Button } from '@react-email/components'
export function ChallengeResultEmail({ agentName, placement, challengeTitle, score }: Props) {
return (
<Html>
<Head />
<Preview>Your agent placed #{placement} in {challengeTitle}</Preview>
<Body style={{ backgroundColor: '#1A1A1A', color: '#F5F0E8', fontFamily: 'sans-serif' }}>
<Container style={{ maxWidth: 600, margin: '0 auto', padding: 40 }}>
<Text style={{ fontSize: 24, fontWeight: 'bold' }}>
🏆 Challenge Results
</Text>
<Text>
{agentName} placed <strong>#{placement}</strong> in "{challengeTitle}"
with a score of {score}/30.
</Text>
<Button
href="https://agentarena.com/results"
style={{ backgroundColor: '#C8A97E', color: '#1A1A1A', padding: '12px 24px', borderRadius: 9999 }}
>
View Full Results
</Button>
</Container>
</Body>
</Html>
)
}
// lib/email.ts
import { Resend } from 'resend'
import { ChallengeResultEmail } from '@/emails/challenge-result'
const resend = new Resend(process.env.RESEND_API_KEY)
export async function sendChallengeResult(to: string, data: ChallengeResultData) {
try {
await resend.emails.send({
from: 'Agent Arena <notifications@agentarena.com>',
to,
subject: `Your agent placed #${data.placement} in ${data.challengeTitle}`,
react: ChallengeResultEmail(data),
})
} catch (error) {
// Log but don't crash — email failure shouldn't block the operation
console.error('[email] Failed to send challenge result:', error)
}
}
Deliverability Fundamentals
| Factor |
Target |
Impact |
| Spam complaint rate |
<0.1% |
Gmail enforces strictly. Above = spam folder. |
| Bounce rate |
<2% |
Remove hard bounces immediately |
| Authentication |
SPF + DKIM + DMARC |
All three required for inbox placement |
| Unsubscribe |
One-click List-Unsubscribe header |
Required by Gmail/Yahoo since Feb 2024 |
| Sender reputation |
Build gradually |
Ramp up volume slowly on new domains |
Gmail/Yahoo Requirements (Since Feb 2024)
- SPF or DKIM authentication (both preferred)
- DMARC policy (at least
p=none)
- One-click unsubscribe header on bulk email
- Spam complaint rate below 0.1%
- Valid forward/reverse DNS for sending IP
Bounce Handling
// Webhook from email provider
async function handleBounce(event: EmailEvent) {
if (event.type === 'bounce') {
if (event.bounceType === 'hard') {
// Invalid email — remove immediately
await supabase.from('users').update({ email_verified: false }).eq('email', event.email)
// Don't send to this address again
await supabase.from('suppression_list').upsert({ email: event.email, reason: 'hard_bounce' })
}
// Soft bounces (mailbox full) — retry 3x, then suppress
}
}
Sources
- resend/react-email component library
- resend/resend-node SDK
- Gmail sender guidelines (2024 update)
- DMARC.org specification
Changelog
- 2026-03-21: Initial skill — email system architecture
1---2name: email-system-architecture3description: Email infrastructure — transactional vs marketing vs cold, React Email templates, Resend integration, deliverability fundamentals, and review checklist.4---56# Email System Architecture78## Review Checklist910- [ ] Transactional and cold email use SEPARATE domains11- [ ] React Email templates tested in Gmail, Outlook, Apple Mail12- [ ] Unsubscribe link in every marketing/notification email13- [ ] SPF/DKIM/DMARC configured on sending domain14- [ ] Bounce handling implemented (hard bounces removed)15- [ ] Email sending is async (doesn't block API response)16- [ ] Failed sends logged but don't crash the operation1718---1920## Three Email Categories (NEVER Mix Infrastructure)2122| Category | Purpose | Service | Domain |23|----------|---------|---------|--------|24| **Transactional** | Password reset, purchase confirmation, challenge result | Resend, Postmark, SES | `notifications@agentarena.com` |25| **Marketing** | Newsletter, product updates | Resend, ConvertKit | `updates@agentarena.com` |26| **Cold outreach** | First contact (OUTBOUND) | Instantly, SmartLead | `hello@outbound-domain.com` |2728**Rule:** If cold email domain gets blacklisted, password resets must still work. SEPARATE domains.2930## React Email + Resend Pattern3132```tsx33// emails/challenge-result.tsx34import { Html, Head, Preview, Body, Container, Text, Button } from '@react-email/components'3536export function ChallengeResultEmail({ agentName, placement, challengeTitle, score }: Props) {37 return (38 <Html>39 <Head />40 <Preview>Your agent placed #{placement} in {challengeTitle}</Preview>41 <Body style={{ backgroundColor: '#1A1A1A', color: '#F5F0E8', fontFamily: 'sans-serif' }}>42 <Container style={{ maxWidth: 600, margin: '0 auto', padding: 40 }}>43 <Text style={{ fontSize: 24, fontWeight: 'bold' }}>44 🏆 Challenge Results45 </Text>46 <Text>47 {agentName} placed <strong>#{placement}</strong> in "{challengeTitle}" 48 with a score of {score}/30.49 </Text>50 <Button51 href="https://agentarena.com/results"52 style={{ backgroundColor: '#C8A97E', color: '#1A1A1A', padding: '12px 24px', borderRadius: 9999 }}53 >54 View Full Results55 </Button>56 </Container>57 </Body>58 </Html>59 )60}61```6263```ts64// lib/email.ts65import { Resend } from 'resend'66import { ChallengeResultEmail } from '@/emails/challenge-result'6768const resend = new Resend(process.env.RESEND_API_KEY)6970export async function sendChallengeResult(to: string, data: ChallengeResultData) {71 try {72 await resend.emails.send({73 from: 'Agent Arena <notifications@agentarena.com>',74 to,75 subject: `Your agent placed #${data.placement} in ${data.challengeTitle}`,76 react: ChallengeResultEmail(data),77 })78 } catch (error) {79 // Log but don't crash — email failure shouldn't block the operation80 console.error('[email] Failed to send challenge result:', error)81 }82}83```8485## Deliverability Fundamentals8687| Factor | Target | Impact |88|--------|--------|--------|89| Spam complaint rate | <0.1% | Gmail enforces strictly. Above = spam folder. |90| Bounce rate | <2% | Remove hard bounces immediately |91| Authentication | SPF + DKIM + DMARC | All three required for inbox placement |92| Unsubscribe | One-click `List-Unsubscribe` header | Required by Gmail/Yahoo since Feb 2024 |93| Sender reputation | Build gradually | Ramp up volume slowly on new domains |9495### Gmail/Yahoo Requirements (Since Feb 2024)961. SPF or DKIM authentication (both preferred)972. DMARC policy (at least `p=none`)983. One-click unsubscribe header on bulk email994. Spam complaint rate below 0.1%1005. Valid forward/reverse DNS for sending IP101102### Bounce Handling103```ts104// Webhook from email provider105async function handleBounce(event: EmailEvent) {106 if (event.type === 'bounce') {107 if (event.bounceType === 'hard') {108 // Invalid email — remove immediately109 await supabase.from('users').update({ email_verified: false }).eq('email', event.email)110 // Don't send to this address again111 await supabase.from('suppression_list').upsert({ email: event.email, reason: 'hard_bounce' })112 }113 // Soft bounces (mailbox full) — retry 3x, then suppress114 }115}116```117118## Sources119- resend/react-email component library120- resend/resend-node SDK121- Gmail sender guidelines (2024 update)122- DMARC.org specification123124## Changelog125- 2026-03-21: Initial skill — email system architecture