email-delivery

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Email Delivery Skill

邮件投递技能

Comprehensive patterns and templates for implementing robust email delivery with Resend, covering single emails, batch operations, scheduled delivery, and attachment handling.
本技能提供使用Resend实现可靠邮件投递的全面模式与模板,涵盖单封邮件发送、批量操作、定时投递以及附件处理。

Use When

适用场景

  • Building transactional email systems (confirmations, notifications, alerts)
  • Implementing batch email campaigns (up to 100 recipients per request)
  • Setting up scheduled/delayed email delivery
  • Handling file attachments, buffers, or URL-based attachments
  • Adding reply-to, CC, and BCC functionality
  • Creating email templates with variables and dynamic content
  • Implementing retry logic and delivery error handling
  • 构建事务性邮件系统(确认邮件、通知、告警)
  • 实现批量邮件营销活动(单次请求最多支持100个收件人)
  • 配置邮件定时/延迟投递
  • 处理文件附件、缓冲区数据或基于URL的附件
  • 添加回复地址、抄送(CC)和密送(BCC)功能
  • 创建包含变量与动态内容的邮件模板
  • 实现重试逻辑与投递错误处理

Core Patterns

核心模式

1. Single Email Sending

1. 单封邮件发送

Transactional emails for immediate delivery with minimal latency:
typescript
import { Resend } from 'resend';

const resend = new Resend('your_resend_key_here');

async function sendTransactionalEmail() {
  const { data, error } = await resend.emails.send({
    from: 'notifications@example.com',
    to: 'user@example.com',
    subject: 'Welcome to Example',
    html: '<h1>Welcome!</h1><p>Thank you for signing up.</p>',
  });

  if (error) {
    console.error('Failed to send email:', error);
    return null;
  }

  return data;
}
事务性邮件,实现低延迟即时投递:
typescript
import { Resend } from 'resend';

const resend = new Resend('your_resend_key_here');

async function sendTransactionalEmail() {
  const { data, error } = await resend.emails.send({
    from: 'notifications@example.com',
    to: 'user@example.com',
    subject: 'Welcome to Example',
    html: '<h1>Welcome!</h1><p>Thank you for signing up.</p>',
  });

  if (error) {
    console.error('Failed to send email:', error);
    return null;
  }

  return data;
}

2. Batch Email Sending

2. 批量邮件发送

Bulk operations for sending up to 100 emails in a single request:
typescript
async function sendBatchEmails(recipients: Array<{email: string; name: string}>) {
  const emails = recipients.map(recipient => ({
    from: 'newsletter@example.com',
    to: recipient.email,
    subject: `Hello ${recipient.name}!`,
    html: `<p>Welcome ${recipient.name}</p>`,
  }));

  const { data, error } = await resend.batch.send(emails);

  if (error) {
    console.error('Batch send failed:', error);
    return null;
  }

  return data;
}
批量操作,单次请求最多发送100封邮件:
typescript
async function sendBatchEmails(recipients: Array<{email: string; name: string}>) {
  const emails = recipients.map(recipient => ({
    from: 'newsletter@example.com',
    to: recipient.email,
    subject: `Hello ${recipient.name}!`,
    html: `<p>Welcome ${recipient.name}</p>`,
  }));

  const { data, error } = await resend.batch.send(emails);

  if (error) {
    console.error('Batch send failed:', error);
    return null;
  }

  return data;
}

3. Scheduled Email Delivery

3. 定时邮件投递

Time-based delivery for emails sent at specific times:
typescript
async function scheduleEmail(scheduledAt: Date) {
  const { data, error } = await resend.emails.send({
    from: 'marketing@example.com',
    to: 'user@example.com',
    subject: 'Scheduled Message',
    html: '<p>This was scheduled!</p>',
    scheduled_at: scheduledAt.toISOString(),
  });

  if (error) {
    console.error('Failed to schedule email:', error);
    return null;
  }

  return data;
}
基于时间的投递,在指定时间发送邮件:
typescript
async function scheduleEmail(scheduledAt: Date) {
  const { data, error } = await resend.emails.send({
    from: 'marketing@example.com',
    to: 'user@example.com',
    subject: 'Scheduled Message',
    html: '<p>This was scheduled!</p>',
    scheduled_at: scheduledAt.toISOString(),
  });

  if (error) {
    console.error('Failed to schedule email:', error);
    return null;
  }

  return data;
}

4. Attachment Handling

4. 附件处理

File attachments from files, buffers, or URLs:
文件附件,支持从文件、缓冲区或URL获取:

File-based Attachment

文件型附件

typescript
import fs from 'fs';
import path from 'path';

async function sendWithFileAttachment(filePath: string) {
  const fileContent = fs.readFileSync(filePath);
  const fileName = path.basename(filePath);

  const { data, error } = await resend.emails.send({
    from: 'documents@example.com',
    to: 'recipient@example.com',
    subject: 'Your Document',
    html: '<p>Please find attached your document.</p>',
    attachments: [
      {
        filename: fileName,
        content: fileContent,
      },
    ],
  });

  return { data, error };
}
typescript
import fs from 'fs';
import path from 'path';

async function sendWithFileAttachment(filePath: string) {
  const fileContent = fs.readFileSync(filePath);
  const fileName = path.basename(filePath);

  const { data, error } = await resend.emails.send({
    from: 'documents@example.com',
    to: 'recipient@example.com',
    subject: 'Your Document',
    html: '<p>Please find attached your document.</p>',
    attachments: [
      {
        filename: fileName,
        content: fileContent,
      },
    ],
  });

  return { data, error };
}

Buffer-based Attachment

缓冲区型附件

typescript
async function sendWithBufferAttachment(buffer: Buffer, filename: string) {
  const { data, error } = await resend.emails.send({
    from: 'reports@example.com',
    to: 'user@example.com',
    subject: 'Monthly Report',
    html: '<p>Your monthly report is attached.</p>',
    attachments: [
      {
        filename: filename,
        content: buffer,
      },
    ],
  });

  return { data, error };
}
typescript
async function sendWithBufferAttachment(buffer: Buffer, filename: string) {
  const { data, error } = await resend.emails.send({
    from: 'reports@example.com',
    to: 'user@example.com',
    subject: 'Monthly Report',
    html: '<p>Your monthly report is attached.</p>',
    attachments: [
      {
        filename: filename,
        content: buffer,
      },
    ],
  });

  return { data, error };
}

URL-based Attachment

URL型附件

typescript
async function sendWithUrlAttachment(fileUrl: string) {
  const response = await fetch(fileUrl);
  const buffer = await response.arrayBuffer();

  const { data, error } = await resend.emails.send({
    from: 'notifications@example.com',
    to: 'user@example.com',
    subject: 'Download Your File',
    html: '<p>Your file is ready.</p>',
    attachments: [
      {
        filename: 'document.pdf',
        content: Buffer.from(buffer),
      },
    ],
  });

  return { data, error };
}
typescript
async function sendWithUrlAttachment(fileUrl: string) {
  const response = await fetch(fileUrl);
  const buffer = await response.arrayBuffer();

  const { data, error } = await resend.emails.send({
    from: 'notifications@example.com',
    to: 'user@example.com',
    subject: 'Download Your File',
    html: '<p>Your file is ready.</p>',
    attachments: [
      {
        filename: 'document.pdf',
        content: Buffer.from(buffer),
      },
    ],
  });

  return { data, error };
}

5. Reply-To and CC/BCC

5. 回复地址与抄送/密送

Message routing with multiple recipients and reply addresses:
typescript
async function sendWithRouting(mainRecipient: string) {
  const { data, error } = await resend.emails.send({
    from: 'support@example.com',
    to: mainRecipient,
    reply_to: 'support-team@example.com',
    cc: ['manager@example.com'],
    bcc: ['archive@example.com'],
    subject: 'Support Ticket #12345',
    html: '<p>We received your support request.</p>',
  });

  return { data, error };
}
消息路由,支持多收件人与指定回复地址:
typescript
async function sendWithRouting(mainRecipient: string) {
  const { data, error } = await resend.emails.send({
    from: 'support@example.com',
    to: mainRecipient,
    reply_to: 'support-team@example.com',
    cc: ['manager@example.com'],
    bcc: ['archive@example.com'],
    subject: 'Support Ticket #12345',
    html: '<p>We received your support request.</p>',
  });

  return { data, error };
}

Python Patterns

Python实现模式

Single Email (Python)

单封邮件(Python)

python
import os
from resend import Resend

client = Resend(api_key=os.environ.get("RESEND_API_KEY"))

def send_email():
    email = {
        "from": "notifications@example.com",
        "to": "user@example.com",
        "subject": "Welcome",
        "html": "<h1>Welcome!</h1>",
    }

    response = client.emails.send(email)
    return response
python
import os
from resend import Resend

client = Resend(api_key=os.environ.get("RESEND_API_KEY"))

def send_email():
    email = {
        "from": "notifications@example.com",
        "to": "user@example.com",
        "subject": "Welcome",
        "html": "<h1>Welcome!</h1>",
    }

    response = client.emails.send(email)
    return response

Batch Email (Python)

批量邮件(Python)

python
def send_batch_emails(recipients):
    emails = [
        {
            "from": "newsletter@example.com",
            "to": recipient["email"],
            "subject": f"Hello {recipient['name']}",
            "html": f"<p>Welcome {recipient['name']}</p>",
        }
        for recipient in recipients
    ]

    response = client.batch.send(emails)
    return response
python
def send_batch_emails(recipients):
    emails = [
        {
            "from": "newsletter@example.com",
            "to": recipient["email"],
            "subject": f"Hello {recipient['name']}",
            "html": f"<p>Welcome {recipient['name']}</p>",
        }
        for recipient in recipients
    ]

    response = client.batch.send(emails)
    return response

File Attachment (Python)

文件附件(Python)

python
def send_with_attachment(file_path):
    with open(file_path, 'rb') as f:
        file_content = f.read()

    email = {
        "from": "documents@example.com",
        "to": "recipient@example.com",
        "subject": "Your Document",
        "html": "<p>Document attached.</p>",
        "attachments": [
            {
                "filename": "document.pdf",
                "content": file_content,
            }
        ],
    }

    response = client.emails.send(email)
    return response
python
def send_with_attachment(file_path):
    with open(file_path, 'rb') as f:
        file_content = f.read()

    email = {
        "from": "documents@example.com",
        "to": "recipient@example.com",
        "subject": "Your Document",
        "html": "<p>Document attached.</p>",
        "attachments": [
            {
                "filename": "document.pdf",
                "content": file_content,
            }
        ],
    }

    response = client.emails.send(email)
    return response

Template Variables

模板变量

Environment Variables Required

所需环境变量

bash
RESEND_API_KEY=your_resend_key_here
RESEND_FROM_EMAIL=your-verified-email@example.com
bash
RESEND_API_KEY=your_resend_key_here
RESEND_FROM_EMAIL=your-verified-email@example.com

Email Template Variables

邮件模板变量

typescript
interface EmailPayload {
  from: string;              // Verified sender email
  to: string | string[];     // Recipient(s)
  cc?: string[];            // Carbon copy recipients
  bcc?: string[];           // Blind carbon copy
  reply_to?: string;        // Reply-to address
  subject: string;          // Email subject
  html?: string;            // HTML content
  text?: string;            // Plain text fallback
  attachments?: Array<{
    filename: string;
    content: Buffer | string;
  }>;
  scheduled_at?: string;    // ISO 8601 datetime for scheduling
  tags?: Array<{
    name: string;
    value: string;
  }>;
}
typescript
interface EmailPayload {
  from: string;              // Verified sender email
  to: string | string[];     // Recipient(s)
  cc?: string[];            // Carbon copy recipients
  bcc?: string[];           // Blind carbon copy
  reply_to?: string;        // Reply-to address
  subject: string;          // Email subject
  html?: string;            // HTML content
  text?: string;            // Plain text fallback
  attachments?: Array<{
    filename: string;
    content: Buffer | string;
  }>;
  scheduled_at?: string;    // ISO 8601 datetime for scheduling
  tags?: Array<{
    name: string;
    value: string;
  }>;
}

Best Practices

最佳实践

Error Handling

错误处理

Always implement retry logic for transient failures:
typescript
async function sendWithRetry(emailPayload, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    const { data, error } = await resend.emails.send(emailPayload);

    if (!error) return { data, success: true };

    if (error.message?.includes('rate_limit') && attempt < maxRetries) {
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
      continue;
    }

    return { error, success: false };
  }
}
始终为临时故障实现重试逻辑:
typescript
async function sendWithRetry(emailPayload, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    const { data, error } = await resend.emails.send(emailPayload);

    if (!error) return { data, success: true };

    if (error.message?.includes('rate_limit') && attempt < maxRetries) {
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
      continue;
    }

    return { error, success: false };
  }
}

Rate Limiting

速率限制

Resend has rate limits. For batch operations over 100 emails:
typescript
async function sendLargeBatch(emails: EmailPayload[]) {
  const batchSize = 100;
  const results = [];

  for (let i = 0; i < emails.length; i += batchSize) {
    const batch = emails.slice(i, i + batchSize);
    const { data, error } = await resend.batch.send(batch);

    if (error) {
      console.error(`Batch ${Math.floor(i / batchSize) + 1} failed:`, error);
      results.push({ success: false, error });
    } else {
      results.push({ success: true, data });
    }

    // Rate limit handling - wait between batches
    if (i + batchSize < emails.length) {
      await new Promise(resolve => setTimeout(resolve, 1000));
    }
  }

  return results;
}
Resend存在速率限制。对于超过100封邮件的批量操作:
typescript
async function sendLargeBatch(emails: EmailPayload[]) {
  const batchSize = 100;
  const results = [];

  for (let i = 0; i < emails.length; i += batchSize) {
    const batch = emails.slice(i, i + batchSize);
    const { data, error } = await resend.batch.send(batch);

    if (error) {
      console.error(`Batch ${Math.floor(i / batchSize) + 1} failed:`, error);
      results.push({ success: false, error });
    } else {
      results.push({ success: true, data });
    }

    // Rate limit handling - wait between batches
    if (i + batchSize < emails.length) {
      await new Promise(resolve => setTimeout(resolve, 1000));
    }
  }

  return results;
}

Template Best Practices

模板最佳实践

  • Use responsive HTML templates
  • Always provide text fallback
  • Test across email clients
  • Include unsubscribe links for marketing emails
  • Avoid large attachments (keep under 25MB)
  • 使用响应式HTML模板
  • 始终提供纯文本备选内容
  • 在多邮件客户端中进行测试
  • 营销邮件中包含退订链接
  • 避免过大附件(保持在25MB以下)

Examples Directory Structure

示例目录结构

  • single-email/
    - Basic transactional email patterns
  • batch-emails/
    - Bulk sending with 50-100 recipients
  • attachments/
    - File, buffer, and URL attachment handling
  • scheduled/
    - Time-based delivery scheduling
See individual example README files for complete code and usage patterns.
  • single-email/
    - 基础事务性邮件模式
  • batch-emails/
    - 支持50-100个收件人的批量发送
  • attachments/
    - 文件、缓冲区与URL附件处理
  • scheduled/
    - 基于时间的投递调度
查看各示例目录下的README文件获取完整代码与使用模式。

Related Skills

相关技能

  • email-templates - HTML template management and rendering
  • email-validation - Recipient address validation
  • email-webhooks - Delivery event tracking and bounce handling
  • email-templates - HTML模板管理与渲染
  • email-validation - 收件人地址验证
  • email-webhooks - 投递事件追踪与退信处理

Resources

资源

Security Notes

安全注意事项

  • API keys should be stored in environment variables (never hardcoded)
  • Use
    RESEND_API_KEY
    from secure secret management
  • Verify sender emails before using in production
  • Implement authentication for email submission endpoints
  • Log email events for compliance and debugging
  • API密钥应存储在环境变量中(切勿硬编码)
  • 从安全的密钥管理系统获取
    RESEND_API_KEY
  • 生产环境使用前验证发件人邮箱
  • 为邮件提交端点实现认证机制
  • 记录邮件事件以满足合规性与调试需求