pinme-email

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

PinMe Worker Email API Integration

PinMe Worker 邮件API集成

Guides how to call PinMe platform's email sending API in a PinMe Worker (TypeScript).
指导如何在PinMe Worker(TypeScript)中调用PinMe平台的邮件发送API。

Environment Variables

环境变量

The following environment variables are automatically injected when the Worker is created — no manual configuration needed:
typescript
// backend/src/worker.ts
export interface Env {
  DB: D1Database;
  API_KEY: string;      // Project API Key — used for send_email authentication
  BASE_URL?: string;    // Optional override for PinMe API base URL, defaults to https://pinme.cloud
}
API_KEY
is the sole credential for the Worker to call PinMe platform APIs. When
BASE_URL
is not set, it defaults to
https://pinme.cloud
.

创建Worker时会自动注入以下环境变量——无需手动配置:
typescript
// backend/src/worker.ts
export interface Env {
  DB: D1Database;
  API_KEY: string;      // Project API Key — 用于send_email认证
  BASE_URL?: string;    // 可选的PinMe API基础URL覆盖,默认值为https://pinme.cloud
}
API_KEY
是Worker调用PinMe平台API的唯一凭证。当未设置
BASE_URL
时,默认值为
https://pinme.cloud

Send Email API

发送邮件API

Endpoint:
POST {BASE_URL}/api/v4/send_email
Authentication:
X-API-Key
header (using
env.API_KEY
) Sender: Automatically set to
{project_name}@pinme.cloud
端点:
POST {BASE_URL}/api/v4/send_email
认证方式:
X-API-Key
请求头(使用
env.API_KEY
发件人: 自动设置为
{project_name}@pinme.cloud

Request Format

请求格式

json
{
  "to": "user@example.com",
  "subject": "Your verification code",
  "html": "<p>Your code is <strong>123456</strong></p>"
}
FieldTypeRequiredDescription
to
stringYesRecipient email address
subject
stringYesEmail subject
html
stringYesHTML body
json
{
  "to": "user@example.com",
  "subject": "Your verification code",
  "html": "<p>Your code is <strong>123456</strong></p>"
}
字段类型必填描述
to
string收件人邮箱地址
subject
string邮件主题
html
stringHTML邮件正文

Response Format

响应格式

Success (200):
json
{ "code": 200, "msg": "ok", "data": { "ok": true } }
Errors:
HTTP StatusMeaningdata.error Example
401API Key missing or invalid
"X-API-Key header is required"
/
"Invalid API key"
400Parameter validation failed
"Invalid email address"
/
"Subject is required"
500Email service error
"Failed to send email"
成功(200):
json
{ "code": 200, "msg": "ok", "data": { "ok": true } }
错误:
HTTP状态码含义data.error示例
401API密钥缺失或无效
"X-API-Key header is required"
/
"Invalid API key"
400参数验证失败
"Invalid email address"
/
"Subject is required"
500邮件服务错误
"Failed to send email"

Worker Example Code

Worker示例代码

typescript
async function sendEmail(env: Env, to: string, subject: string, html: string): Promise<{ ok: boolean; error?: string }> {
  const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';
  const resp = await fetch(`${baseUrl}/api/v4/send_email`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': env.API_KEY,
    },
    body: JSON.stringify({ to, subject, html }),
  });

  const result = await resp.json() as { code: number; msg: string; data?: { ok?: boolean; error?: string } };

  if (resp.status !== 200 || result.code !== 200) {
    return { ok: false, error: result.data?.error || result.msg || 'Unknown error' };
  }
  return { ok: true };
}

// Usage in routes
async function handleSendVerification(request: Request, env: Env): Promise<Response> {
  const { email } = await request.json() as { email: string };
  const code = Math.random().toString().slice(2, 8);

  const result = await sendEmail(env, email, 'Verification Code',
    `<p>Your code is <strong>${code}</strong></p>`);

  if (!result.ok) {
    return json({ error: result.error }, 500);
  }
  return json({ ok: true });
}

typescript
async function sendEmail(env: Env, to: string, subject: string, html: string): Promise<{ ok: boolean; error?: string }> {
  const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';
  const resp = await fetch(`${baseUrl}/api/v4/send_email`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': env.API_KEY,
    },
    body: JSON.stringify({ to, subject, html }),
  });

  const result = await resp.json() as { code: number; msg: string; data?: { ok?: boolean; error?: string } };

  if (resp.status !== 200 || result.code !== 200) {
    return { ok: false, error: result.data?.error || result.msg || 'Unknown error' };
  }
  return { ok: true };
}

// 路由中的使用示例
async function handleSendVerification(request: Request, env: Env): Promise<Response> {
  const { email } = await request.json() as { email: string };
  const code = Math.random().toString().slice(2, 8);

  const result = await sendEmail(env, email, 'Verification Code',
    `<p>Your code is <strong>${code}</strong></p>`);

  if (!result.ok) {
    return json({ error: result.error }, 500);
  }
  return json({ ok: true });
}

Error Handling Pattern

错误处理模式

PinMe platform API unified response format:
typescript
interface PinmeResponse<T = unknown> {
  code: number;   // 200=success, other=failure
  msg: string;    // "ok" | "error" | "invalid params"
  data?: T;       // Business data on success, may contain { error: string } on failure
}
PinMe平台API统一响应格式:
typescript
interface PinmeResponse<T = unknown> {
  code: number;   // 200=成功,其他=失败
  msg: string;    // "ok" | "error" | "invalid params"
  data?: T;       // 成功时返回业务数据,失败时可能包含{ error: string }
}

Recommended Unified Error Handler

推荐的统一错误处理器

typescript
async function callPinmeAPI<T>(url: string, apiKey: string, body: unknown): Promise<{ data?: T; error?: string }> {
  let resp: Response;
  try {
    resp = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', 'X-API-Key': apiKey },
      body: JSON.stringify(body),
    });
  } catch {
    return { error: 'Network error' };
  }

  if (!resp.ok) {
    try {
      const err = await resp.json() as PinmeResponse;
      return { error: err.data && typeof err.data === 'object' && 'error' in err.data
        ? (err.data as { error: string }).error
        : err.msg || `HTTP ${resp.status}` };
    } catch {
      return { error: `HTTP ${resp.status}` };
    }
  }

  const result = await resp.json() as PinmeResponse<T>;
  if (result.code !== 200) {
    return { error: result.data && typeof result.data === 'object' && 'error' in result.data
      ? (result.data as { error: string }).error
      : result.msg };
  }
  return { data: result.data as T };
}
typescript
async function callPinmeAPI<T>(url: string, apiKey: string, body: unknown): Promise<{ data?: T; error?: string }> {
  let resp: Response;
  try {
    resp = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', 'X-API-Key': apiKey },
      body: JSON.stringify(body),
    });
  } catch {
    return { error: 'Network error' };
  }

  if (!resp.ok) {
    try {
      const err = await resp.json() as PinmeResponse;
      return { error: err.data && typeof err.data === 'object' && 'error' in err.data
        ? (err.data as { error: string }).error
        : err.msg || `HTTP ${resp.status}` };
    } catch {
      return { error: `HTTP ${resp.status}` };
    }
  }

  const result = await resp.json() as PinmeResponse<T>;
  if (result.code !== 200) {
    return { error: result.data && typeof result.data === 'object' && 'error' in result.data
      ? (result.data as { error: string }).error
      : result.msg };
  }
  return { data: result.data as T };
}

Usage Example

使用示例

typescript
const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';

// Send email
const emailResult = await callPinmeAPI<{ ok: boolean }>(
  `${baseUrl}/api/v4/send_email`, env.API_KEY,
  { to: 'user@example.com', subject: 'Hello', html: '<p>Hi</p>' },
);
if (emailResult.error) return json({ error: emailResult.error }, 500);
typescript
const baseUrl = env.BASE_URL ?? 'https://pinme.cloud';

// 发送邮件
const emailResult = await callPinmeAPI<{ ok: boolean }>(
  `${baseUrl}/api/v4/send_email`, env.API_KEY,
  { to: 'user@example.com', subject: 'Hello', html: '<p>Hi</p>' },
);
if (emailResult.error) return json({ error: emailResult.error }, 500);