Skip to content
Deployment
Skill

/pinme-email

Use this skill when a PinMe project (Worker TypeScript) needs to integrate email sending (send_email). Guides AI to generate correct Worker TS code.

From plugin
pinme
3.8k7 skills

Claude Code

$ npx -y skills add glitternetwork/pinme --skill pinme-email --agent claude-code

SKILL.md

pinme-email.SKILL.md
name: pinme-email
description: Use this skill when a PinMe project (Worker TypeScript) needs to integrate email sending (send_email). Guides AI to generate correct Worker TS code.

PinMe Worker Email API Integration

Guides how to call PinMe platform's email sending API in a PinMe Worker (TypeScript).

Environment Variables

The following environment variables are automatically injected when the Worker is created — no manual configuration needed:

// 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`.

---

Send Email 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`

Request Format

{
  "to": "user@example.com",
  "subject": "Your verification code",
  "html": "<p>Your code is <strong>123456</strong></p>"
}

| Field | Type | Required | Description | |-------|------|----------|-------------| | `to` | string | Yes | Recipient email address | | `subject` | string | Yes | Email subject | | `html` | string | Yes | HTML body |

Response Format

**Success (200):**

{ "code": 200, "msg": "ok", "data": { "ok": true } }

**Errors:**

| HTTP Status | Meaning | data.error Example | |-------------|---------|-------------------| | 401 | API Key missing or invalid | `"X-API-Key header is required"` / `"Invalid API key"` | | 400 | Parameter validation failed | `"Invalid email address"` / `"Subject is required"` | | 500 | Email service error | `"Failed to send email"` |

Worker Example Code

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 });
}

---

Error Handling Pattern

PinMe platform API unified response format:

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
}

Recommended Unified Error Handler

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

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);
Read more
@glitternetwork
Ships withpinme

PinMe is a zero-config deployment CLI focused on one-command creation and deployment for full-stack projects. It lets you quickly set up and launch a complete project with an integrated frontend, Worker backend, and database, without tedious configuration.

Stars on GitHub

Momentum

stars in total
3.8k
Star history of glitternetwork/pinme on GitHub, a chart by star-history.com

Other skills on pinme.

pinme-auth

pinme-auth

Use when a PinMe project (Worker TypeScript) needs to integrate user authentication — creating email/password users, verifying…

pinme-llm

pinme-llm

Use this skill when a PinMe project (Worker TypeScript) needs to call OpenRouter-backed LLM APIs, including models,…

pinme-r2

pinme-r2

Use when a PinMe Cloudflare Worker needs R2 object storage, including secure file or image upload, streaming download, metadata…

pinme-share

pinme-share

Use this skill when the user wants to share, publish, or upload a static result through PinMe, especially by generating a static…

pinme-uniwebpay

pinme-uniwebpay

Use when generating, modifying, or reviewing PinMe Worker (Cloudflare Worker TypeScript) code that accepts payments through…

pinme

pinme

Use this skill when the user mentions "pinme", or needs to upload files, store to IPFS, create/publish/deploy websites or…

More skills from other plugins.

configuring-horizon

configuring-horizon

Use this skill whenever the user mentions Horizon by name in a Laravel context. Covers the full Horizon lifecycle: installing…

coolify9d66k
@coollabsio@coollabsioInstall Skill
vercel-cli

vercel-cli

Guides deployment, configuration, and troubleshooting with the Vercel CLI. Use when operating Vercel projects or resources…

vercel11d16k
@vercel@vercelInstall Skill
skypilot

skypilot

Use when launching cloud VMs, Kubernetes pods, or Slurm jobs for GPU/TPU/CPU workloads, training or fine-tuning models on cloud…

@skypilot-org@skypilot-orgInstall Skill
mlx-serve

mlx-serve

Hook an app, game or script up to the local mlx-serve server for LLM chat, embeddings, image, speech, music, sound effect, video…

mlx-serve11d2.2k
@ddalcu@ddalcuInstall Skill

Questions about pinme-email.

Which coding agents can use pinme-email?
pinme-email installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.