mcpbeat

Pinme Email

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

1k tokens
context cost
the whole folder, loaded on every use
1
files
instructions only
0
copies elsewhere
how many repositories repackaged it
3732
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/glitternetwork/pinme --skill pinme-email

The instruction itself

9 sections, as written by the author

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": "[email protected]",
  "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
}
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: '[email protected]', subject: 'Hello', html: '<p>Hi</p>' },
);
if (emailResult.error) return json({ error: emailResult.error }, 500);

How to use it

Copy the folder

Take glitternetwork/pinme-email from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.