Generated Email

Outbound emails grounded in real facts about the recipient

Live preview

Checking API key

How it works

Every email is one request to Exa's /search endpoint with type: "deep" and an outputSchema that returns a structured object with recipient, subject, and paragraphs fields.

The systemPrompt carries the sender persona (name, product, ICP) plus a tight list of voice rules: contractions, numerals for figures, second-person voice, no clichés, no em dashes. The schema description shapes the body into a greeting, an opener anchored in one recent verifiable fact, a pitch tying that fact to the product, a low-friction CTA, and a signoff.

The body stays clean. No inline citation markers. Sources are flattened from output.grounding and rendered as a favicon row below the email, deduped by domain.

Source code

npm install exa-js
import Exa from "exa-js";
const exa = new Exa("YOUR_API_KEY");

const SENDER = {
  name: "Alex",
  product: "Beam, an AI-powered sales intelligence platform for RevOps teams",
  icp: "B2B SaaS companies with 50-500 employees that use Salesforce",
};

const recipient = "Patrick Collison, CEO at Stripe";

const result = await exa.search(`Research ${recipient}`, {
  type: "deep",
  numResults: 10,
  systemPrompt: `Cold B2B email from ${SENDER.name} at ${SENDER.product} to ${recipient}. Ground in one specific recent verifiable fact. Short, second person, no clichés.`,
  outputSchema: {
    type: "object",
    required: ["recipient", "subject", "paragraphs"],
    properties: {
      recipient: { type: "string", description: "Resolved recipient with role + company" },
      subject: { type: "string", description: "Sentence case, 8 words or less, specific" },
      paragraphs: {
        type: "array",
        description: "Ordered paragraphs: [greeting, opener with recent fact, pitch tying fact to product, CTA, signoff]",
        items: { type: "string" },
      },
    },
  },
  contents: { highlights: true },
});

const { subject, paragraphs } = result.output.content;
const citations = result.output.grounding.flatMap((g) => g.citations);
Ask ExaBot