Use Cases (अपडेट: 2/6/2026)

Claude Code से SendGrid ईमेल सुरक्षित तरीके से कैसे लागू करें

Claude Code से SendGrid ईमेल लागू करें: verified sender, Mail Send API, retry, log और deliverability।

Claude Code से SendGrid ईमेल सुरक्षित तरीके से कैसे लागू करें

SendGrid एक cloud email delivery service है जिससे application API के जरिए email भेज सकती है। इसे contact form confirmation, signup onboarding, daily report, transactional notification और sales follow-up जैसे कामों में इस्तेमाल किया जा सकता है।

जोखिम यह है कि email भेजने का code छोटा दिखता है। अगर आप Claude Code से सिर्फ “SendGrid से email भेजो” कहेंगे, तो API call मिल सकती है, लेकिन verified sender, API key सुरक्षा, retry में duplicate send, bounce handling, spam complaint, provider log और opt-out अक्सर छूट जाते हैं। Email एक बार बाहर चला गया तो वापस नहीं लिया जा सकता। इसलिए code से पहले operational boundary तय करना जरूरी है।

यह guide Twilio SendGrid की official v3 Mail Send API, SendGrid की Validation Error reference और SendGrid website पर आधारित है। इसमें copy-paste runnable Node.js script है जो default में dry-run चलता है, --send के बिना email नहीं भेजता, payload validate करता है, sandbox validation support करता है, temporary failures पर retry करता है और local send log से simple idempotency guard देता है।

बुनियादी पढ़ाई के लिए Claude Code email automation, API development, environment variable management और security best practices भी साथ में देखें।

Code से पहले SendGrid की मूल बातें

SendGrid Mail Send API में JSON को POST https://api.sendgrid.com/v3/mail/send पर भेजा जाता है और header में Authorization: Bearer SENDGRID_API_KEY दिया जाता है। API call आसान है, लेकिन production में इन बातों की जांच जरूरी है।

चीजसरल अर्थक्या जांचें
Verified SenderSendGrid ने पुष्टि की है कि यह from address email भेज सकता हैछोटे test में Single Sender, production में Domain Authentication
Domain AuthenticationDNS से साबित करना कि आपका domain SendGrid से भेज सकता हैSPF/DKIM records verify होने के बाद ही real traffic
API KeyServer से SendGrid API call करने का secretकेवल server environment variable में रखें, browser या Git में नहीं
personalizationsRecipient-specific data जैसे to, subject, custom args या template dataएक personalization में सिर्फ एक recipient रखें
SuppressionBounce, complaint या unsubscribe के कारण जिन्हें email नहीं भेजनाSendGrid call से पहले अपनी suppression list check करें
Provider logHTTP status, response body और x-message-idSupport, debugging और duplicate रोकने के लिए save करें

SPF एक DNS record है जो बताता है कि कौन से servers आपके domain से email भेज सकते हैं। DKIM एक signature है जिससे receiver देखता है कि message authorized है और बदला नहीं गया। DMARC वह policy है जो SPF या DKIM alignment fail होने पर receiver को दिशा देती है। शुरुआती स्तर पर इतना समझना काफी है कि sender authentication deliverability की पहचान है।

from में कोई भी Gmail address डालकर शुरू न करें। Local test के लिए SendGrid Single Sender verify करें। Production में अपना domain authenticate करें और product, support या team address से भेजें। कई validation errors invalid from, गलत personalizations, missing content या template गलती से आते हैं।

चार practical use cases

सभी emails को एक generic sendMail helper में न डालें। हर workflow में consent, frequency, tone, failure impact और logging अलग होते हैं।

Use caseExampleजरूरी guardrail
Contact form emailVisitor को confirmation, team को notificationUser input escape करें, admin और visitor mail अलग रखें
Transactional onboardingSignup complete, first login guide, purchase instructionsExpected और useful रखें, बहुत ज्यादा promotion न मिलाएं
Daily report emailRevenue, errors, bookings, course progressIdempotency key रखें ताकि retry duplicate report न बनाए
Sales या outreachMeeting follow-up, proposal, promised resourceOpt-out, sender identity, suppression और local compliance check

Outreach में विशेष सावधानी चाहिए। Technical रूप से भेज पाना, भेजने की अनुमति के बराबर नहीं है। Country, relationship, B2B/B2C और message type के आधार पर नियम बदलते हैं। यह article legal advice नहीं है। कम से कम email भेजने का कारण, sender identity और working opt-out route जरूर दें।

flowchart LR
  App["App / Claude Code change"]
  Validate["Payload validation"]
  Log["Send log और idempotency key"]
  SendGrid["SendGrid Mail Send API"]
  Inbox["Inbox"]
  Events["Bounce / Spam / Unsubscribe"]
  Suppression["Suppression list"]

  App --> Validate --> Log --> SendGrid --> Inbox
  SendGrid --> Events --> Suppression
  Suppression --> Validate

Copy-paste Node.js script

नीचे वाला script Node.js 20 या उससे ऊपर चलता है और कोई dependency नहीं चाहिए। Default mode dry-run है: यह payload print करता है और log लिखता है, लेकिन SendGrid call नहीं करता। Real API call के लिए --send लगाएं। SendGrid से request validate करानी हो पर email deliver न करना हो तो --send --sandbox लगाएं।

// sendgrid-safe-send.mjs
import { createHash } from "node:crypto";
import { existsSync } from "node:fs";
import { readFile, writeFile } from "node:fs/promises";

const ENDPOINT = process.env.SENDGRID_API_BASE ?? "https://api.sendgrid.com/v3/mail/send";
const LOG_PATH = process.env.SENDGRID_SEND_LOG ?? ".sendgrid-send-log.json";
const DRY_RUN = !process.argv.includes("--send");
const SANDBOX = process.argv.includes("--sandbox");
const MAX_ATTEMPTS = Number.parseInt(process.env.SENDGRID_MAX_ATTEMPTS ?? "3", 10);

const recipient = {
  email: process.env.MAIL_TO ?? "recipient@example.com",
  name: process.env.MAIL_TO_NAME ?? "Test Recipient",
};

const message = {
  from: {
    email: process.env.MAIL_FROM ?? "verified-sender@example.com",
    name: process.env.MAIL_FROM_NAME ?? "ClaudeCodeLab Demo",
  },
  reply_to: {
    email: process.env.MAIL_REPLY_TO ?? process.env.MAIL_FROM ?? "verified-sender@example.com",
  },
  personalizations: [
    {
      to: [recipient],
      custom_args: {
        use_case: process.env.MAIL_USE_CASE ?? "dry_run_demo",
      },
    },
  ],
  subject: process.env.MAIL_SUBJECT ?? `SendGrid dry-run test for ${recipient.name}`,
  content: [
    {
      type: "text/plain",
      value: `Hello ${recipient.name},\n\nThis is a safe SendGrid test from Claude Code.\n`,
    },
    {
      type: "text/html",
      value: `<p>Hello ${escapeHtml(recipient.name)},</p><p>This is a safe SendGrid test from Claude Code.</p>`,
    },
  ],
  categories: ["claude-code-demo"],
  mail_settings: {
    sandbox_mode: { enable: SANDBOX },
  },
};

validatePayload(message);
const idempotencyKey = makeIdempotencyKey(message);
for (const personalization of message.personalizations) {
  personalization.custom_args = {
    ...(personalization.custom_args ?? {}),
    idempotency_key: idempotencyKey,
  };
}

await sendWithRetry(message, idempotencyKey);

function validatePayload(payload) {
  if (!Number.isInteger(MAX_ATTEMPTS) || MAX_ATTEMPTS < 1 || MAX_ATTEMPTS > 5) {
    throw new Error("SENDGRID_MAX_ATTEMPTS must be an integer from 1 to 5.");
  }

  assertEmail(payload.from?.email, "from.email");
  if (!DRY_RUN && payload.from.email.endsWith("@example.com")) {
    throw new Error("Set MAIL_FROM to a verified SendGrid sender before using --send.");
  }

  if (!Array.isArray(payload.personalizations) || payload.personalizations.length === 0) {
    throw new Error("personalizations must contain at least one recipient.");
  }

  for (const [index, personalization] of payload.personalizations.entries()) {
    if (!Array.isArray(personalization.to) || personalization.to.length !== 1) {
      throw new Error(`personalizations[${index}].to must contain exactly one recipient.`);
    }
    assertEmail(personalization.to[0]?.email, `personalizations[${index}].to[0].email`);
  }

  if (!payload.subject && !payload.template_id) {
    throw new Error("Provide a subject or a SendGrid template_id.");
  }

  const hasContent = Array.isArray(payload.content)
    && payload.content.some((item) => typeof item.value === "string" && item.value.trim());
  if (!hasContent && !payload.template_id) {
    throw new Error("Provide text/html content or a SendGrid template_id.");
  }
}

function assertEmail(value, field) {
  if (typeof value !== "string" || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
    throw new Error(`${field} must be a valid email address.`);
  }
}

function makeIdempotencyKey(payload) {
  const stableEnvelope = {
    from: payload.from.email.toLowerCase(),
    to: payload.personalizations.map((item) => item.to[0].email.toLowerCase()),
    subject: payload.subject,
    content: payload.content?.map((item) => item.value),
    useCase: payload.personalizations.map((item) => item.custom_args?.use_case ?? ""),
  };
  return createHash("sha256").update(JSON.stringify(stableEnvelope)).digest("hex").slice(0, 32);
}

async function sendWithRetry(payload, idempotencyKey) {
  const log = await readJsonLog();
  const previous = log[idempotencyKey];

  if (previous?.status === "accepted") {
    console.log(`Already accepted by SendGrid. idempotencyKey=${idempotencyKey}`);
    return;
  }
  if (previous?.status === "pending") {
    throw new Error(`A send is already pending. idempotencyKey=${idempotencyKey}`);
  }

  if (DRY_RUN) {
    log[idempotencyKey] = {
      status: "dry-run",
      updatedAt: new Date().toISOString(),
      to: payload.personalizations.map((item) => item.to[0].email),
    };
    await writeJsonLog(log);
    console.log("Dry run only. Add --send to call SendGrid.");
    console.log(JSON.stringify({ idempotencyKey, payload }, null, 2));
    return;
  }

  const apiKey = process.env.SENDGRID_API_KEY;
  if (!apiKey) {
    throw new Error("SENDGRID_API_KEY is required when using --send.");
  }

  log[idempotencyKey] = { status: "pending", updatedAt: new Date().toISOString() };
  await writeJsonLog(log);

  for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt += 1) {
    const response = await fetch(ENDPOINT, {
      method: "POST",
      headers: {
        Authorization: `Bearer ${apiKey}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify(payload),
    });
    const responseBody = await response.text();
    const providerMessageId = response.headers.get("x-message-id");

    if (response.status === 202) {
      log[idempotencyKey] = {
        status: "accepted",
        statusCode: response.status,
        providerMessageId,
        updatedAt: new Date().toISOString(),
      };
      await writeJsonLog(log);
      console.log(`Accepted by SendGrid. idempotencyKey=${idempotencyKey}`);
      return;
    }

    const retryable = response.status === 429 || response.status >= 500;
    log[idempotencyKey] = {
      status: retryable && attempt < MAX_ATTEMPTS ? "retrying" : "failed",
      statusCode: response.status,
      responseBody: responseBody.slice(0, 2000),
      attempt,
      updatedAt: new Date().toISOString(),
    };
    await writeJsonLog(log);

    if (!retryable || attempt === MAX_ATTEMPTS) {
      throw new Error(`SendGrid request failed with HTTP ${response.status}: ${responseBody}`);
    }

    await sleep(Math.min(1000 * 2 ** (attempt - 1), 8000));
  }
}

async function readJsonLog() {
  if (!existsSync(LOG_PATH)) return {};
  return JSON.parse(await readFile(LOG_PATH, "utf8"));
}

async function writeJsonLog(log) {
  await writeFile(LOG_PATH, `${JSON.stringify(log, null, 2)}\n`, "utf8");
}

function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

function escapeHtml(value) {
  return String(value)
    .replaceAll("&", "&amp;")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;")
    .replaceAll('"', "&quot;")
    .replaceAll("'", "&#39;");
}

पहले dry-run चलाएं। Windows PowerShell में:

node .\sendgrid-safe-send.mjs

$env:SENDGRID_API_KEY="SG.xxxxx"
$env:MAIL_FROM="verified@example.com"
$env:MAIL_TO="you@example.net"
node .\sendgrid-safe-send.mjs --send --sandbox

node .\sendgrid-safe-send.mjs --send

macOS या Linux में:

SENDGRID_API_KEY="SG.xxxxx" MAIL_FROM="verified@example.com" MAIL_TO="you@example.net" node sendgrid-safe-send.mjs --send --sandbox

Local JSON log सिर्फ demo के लिए है। Production में इसी idea को Postgres, Redis, SQS, Cloud Tasks या किसी durable queue में रखें। idempotency_key पर unique constraint लगाएं और provider status को business status से अलग रखें।

Claude Code के लिए prompt

Claude Code से सिर्फ function न लिखवाएं। उसे workflow, सुरक्षा और verification की सीमा भी दें।

इस repository में SendGrid email delivery जोड़ें।
Workflows हैं contact form confirmation, signup onboarding, daily reports और sales follow-up.

Constraints:
- SendGrid Mail Send API v3 use करें।
- API key केवल server-side SENDGRID_API_KEY environment variable से पढ़ें।
- सभी scripts default dry-run हों और केवल --send पर भेजें।
- Recipient list expose न हो, इसलिए एक personalization में exactly एक recipient रखें।
- केवल 429 और 5xx पर exponential backoff retry करें।
- भेजने से पहले unsubscribe, bounce और spam complaint suppression check करें।
- provider response, HTTP status, x-message-id और idempotency key save करें।
- Outreach email में opt-out path शामिल करें।
- README में official SendGrid docs link करें।

पहले design table और file list दें। Approval के बाद edit करें।

इस तरह Claude Code consent, suppression, logs और retries पर भी ध्यान देता है। Parallel work वाले repo में file list पहले मिलने से accidental edit scope भी कम होता है।

Common failure cases

Failureक्या होता हैबचाव
API key leakकोई और आपके account से send कर सकता है.env ignore करें, secret scan करें, key rotate करें
Unverified sender400 error, block या poor inbox placementSingle Sender verify या domain authenticate करें
Retry duplicate sendवही report, receipt या follow-up कई बार पहुंचता हैProvider call से पहले send log और idempotency key देखें
Outreach बिना opt-outComplaint और legal risk बढ़ते हैंOpt-out, company identity और reason लिखें
बहुत तेज भेजनाRate limit और reputation समस्याछोटे volume से शुरू करें, bounce और complaint देखें
Provider response न रखनाSupport घटना समझा नहीं पाताStatus, body, x-message-id और recipient hash save करें
Recipient list expose करनाUsers को दूसरों के email दिखते हैंएक personalization में एक recipient रखें

SendGrid का 202 Accepted inbox delivery का प्रमाण नहीं है। इसका अर्थ है कि SendGrid ने request processing के लिए स्वीकार की। Real operation के लिए bounce, block, spam report और unsubscribe events देखना जरूरी है।

Deliverability और CTA

Deliverability सिर्फ DNS से तय नहीं होती। Sender authentication, recipient expectation, sending volume, content clarity, bounce history, complaint rate और unsubscribe experience सब असर डालते हैं। कम से कम sent, accepted, bounce, blocked, spam report और unsubscribe metrics देखें।

ClaudeCodeLab जैसे funnel में CTA context के हिसाब से होना चाहिए। Contact confirmation useful article से link कर सकता है। Onboarding checklist या template दे सकता है। Daily report operational रहना चाहिए। Sales follow-up तभी consultation invite करे जब relationship उचित हो। Real repository में लागू करने के लिए Claude Code training और consulting में SendGrid setup, environment variables, secret scanning, suppression design और logs साथ में design किए जा सकते हैं।

Practical verification result

Masa ने जब यह sample local में test किया, तो सबसे उपयोगी सुरक्षा decision dry-run को default रखना था। बिना flags script ने केवल payload print किया और local log लिखा। MAIL_FROM अगर @example.com था, तो --send लगाने पर भी API call से पहले रुक गया। --send --sandbox से SendGrid request shape validate कर सकता है, बिना email deliver किए। Real projects में local log को unique idempotency constraint वाली database queue से बदलना चाहिए, और bounce, spam complaint, unsubscribe events को send-before suppression check में वापस लाना चाहिए।

#Claude Code #SendGrid #email #API #automation
मुफ़्त

मुफ़्त PDF: Claude Code cheatsheet

Email डालें और commands, review habits तथा safe workflow वाली एक-page PDF पाएँ.

हम आपका data सुरक्षित रखते हैं और spam नहीं भेजते.

Masa

लेखक के बारे में

Masa

Claude Code workflow और team adoption पर काम करने वाला engineer.