> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cognee.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Personalized Email

> Draft email replies that already know what you discussed in meetings, what you promised, and how you write

A plain LLM sees only the email in front of it. This one remembers the call where you made a promise, so its reply keeps it.

## What You'll Build

Your Granola meeting notes, your Gmail inbox and your sent mail go into one cognee memory. When a new email arrives, an agent drafts your reply: the facts come from what was said in your meetings, and the tone comes from how you write. The draft is printed, never sent.

Building the memory takes three `cognee.remember` calls, one per source, and drafting the reply takes two `cognee.recall` calls.

The complete cookbook is
[`examples/cookbooks/personalized_email/`](https://github.com/topoteretes/cognee/tree/dev/examples/cookbooks/personalized_email).

## Try It on Sample Data

The sample is Mira Lang's week. Twelve days ago, on a call, she promised Priya Shah pilot pricing by Friday and said SSO supports SAML today, with OIDC coming next month. Yesterday Priya emailed asking when the pilot can start, whether SSO supports OIDC, and where the pricing is. You need only an [LLM key](/setup-configuration/llm-providers), no Gmail or Granola account.

```bash theme={null}
git clone https://github.com/topoteretes/cognee.git && cd cognee
uv sync
echo 'LLM_API_KEY="your-key"' >> .env
```

`LLM_API_KEY` alone is enough for OpenAI, cognee's default for both the LLM and the embeddings. Other providers, such as Anthropic, Gemini, Azure OpenAI, AWS Bedrock or a local model through Ollama, need a few more lines in the same `.env`: [LLM Providers](/setup-configuration/llm-providers#provider-setup-guides) and [Embedding Providers](/setup-configuration/embedding-providers#provider-setup-guides) list them for each provider. Set both, because embeddings you leave at the default still need an OpenAI key.

<Tabs>
  <Tab title="Terminal">
    ```bash theme={null}
    uv run python examples/cookbooks/personalized_email/personalized_email.py --sample
    ```
  </Tab>

  <Tab title="Coding agent">
    The cognee repo ships a skill for this cookbook, [`.agents/skills/personalized-email/SKILL.md`](https://github.com/topoteretes/cognee/blob/dev/.agents/skills/personalized-email/SKILL.md). Claude Code and Codex find it on their own when you open them in the cognee folder. Ask in plain words, or type `/personalized-email` in Claude Code:

    ```text theme={null}
    Draft a reply to my newest email.
    ```

    With no Gmail or Granola set up, it runs on the sample and says so. Once your accounts are set up, the same request drafts a reply to your real inbox; the skill runs `--check` first and tells you what is missing. It never sends the draft.
  </Tab>
</Tabs>

```text theme={null}
[setup] CLEAR: the cookbook's dataset is forgotten before this run.
[setup] Wrote the sample from setup.py.
[clear] Nothing to forget: the dataset personalized_email does not exist yet.
[ingest_granola] Remembered 2 sample meetings
[ingest_email] Remembered 2 sample inbox emails
[ingest_email] Remembered 3 sample sent emails
[draft] Answering: Pilot start and SSO (from Priya Shah <priya@northwind.example>)
...
[draft] Reply:

To: Priya Shah <priya@northwind.example>
Subject: Re: Pilot start and SSO

Hi Priya,

Yes, we can start the pilot on the first of next month once the order form is signed. SSO is SAML-only for now; OIDC is on track to ship in the third week of next month.

I haven't sent the pilot pricing yet. It's 400 EUR a month for three seats, with the first month free.

Best,
M.
```

Priya's email contains none of these answers. The start condition and the price come from the scoping call. The OIDC date comes from a later product sync Priya was not in. "I haven't sent the pilot pricing yet" comes from the promise in the call and its absence from Mira's sent mail, and "Best, M." comes from that sent mail too. The first run has nothing to forget; a later sample run prints `[clear] Forgot the dataset personalized_email` instead. Your wording will differ from run to run.

## Run It on Your Data

Gmail is required. Granola is optional: without it, pass `--no-granola` to skip meetings. Set up each source you use:

<Tabs>
  <Tab title="Gmail">
    The cookbook reads your mail read-only through a Google OAuth client you create once:

    1. In the [Google Cloud Console](https://console.cloud.google.com/), create or pick a project and enable the **Gmail API**.
    2. Configure the **OAuth consent screen**. While the app is in *Testing*, add your own Google account as a test user.
    3. Go to **Credentials → Create credentials → OAuth client ID**, choose **Desktop app**, and download the JSON file.
    4. Save it as `credentials.json` in the cookbook folder, next to `personalized_email.py`.
    5. Install the Google client libraries with `uv sync --extra gmail`.

    The first run opens a browser so you can allow read access. It then writes `token.json` next to `credentials.json`, with the `gmail.readonly` scope. [Gmail Ingestion](/guides/gmail-ingestion) covers the connector in more detail.
  </Tab>

  <Tab title="Granola">
    The cookbook reads your notes through Granola's API with a personal API key. Creating one needs a Granola Business plan; on Enterprise, a workspace admin enables it first.

    1. In the Granola desktop app, open **Settings → Connectors → API keys** and click **Create new key**.
    2. Choose the **Personal notes** scope and click **Generate API Key**. Copy the key now; Granola shows it only once.
    3. Add it to `.env` at the repo root: `GRANOLA_API_KEY="grn_..."`.

    The API returns only notes that already have an AI summary and a transcript. [Granola's API docs](https://docs.granola.ai/introduction) list the other scopes.
  </Tab>
</Tabs>

* `MY_NAME` (optional): your name as it appears in your email, in `.env`, so the draft speaks as you. A sample run always answers as Mira, whose mailbox the sample is.
* `credentials.json` and `token.json` are git-ignored. Never commit them.

```bash theme={null}
uv run python examples/cookbooks/personalized_email/personalized_email.py --check
uv run python examples/cookbooks/personalized_email/personalized_email.py
uv run python examples/cookbooks/personalized_email/personalized_email.py --days 7
```

`--check` reports what is missing without doing any work. The first run opens a browser so you can let it read your Gmail. Running it again skips content cognee already holds; add `--clear` to forget the dataset first and start over from your sources as they are now. Each script also runs alone, for example `uv run python examples/cookbooks/personalized_email/scripts/draft.py`.

## How It Works

### Step 1: Start From an Empty Memory

Source: [`scripts/clear.py`](https://github.com/topoteretes/cognee/blob/dev/examples/cookbooks/personalized_email/scripts/clear.py)

This step forgets what an earlier run remembered, so old copies never mix with new ones. It runs only with `--clear`, which a sample run turns on by default; `--no-clear` keeps the dataset.

```python theme={null}
await clear()
```

The sample is dated relative to today, so each day's sample differs from yesterday's. Without this step, a second run would add today's meetings next to yesterday's. cognee's part is one call: [`cognee.forget(dataset="personalized_email")`](/core-concepts/main-operations/forget), which deletes the dataset and everything extracted from it. On your own data, use `--clear` only to start over.

### Step 2: Remember Your Meeting Notes

Source: [`scripts/ingest_granola.py`](https://github.com/topoteretes/cognee/blob/dev/examples/cookbooks/personalized_email/scripts/ingest_granola.py)

This step saves your meeting notes so the agent can use them later. It runs unless you pass `--no-granola`.

```python theme={null}
await ingest_granola(args.days, args.sample)
```

The script reads your notes from the last 30 days from Granola's API, each with its attendees and transcript; pass `--days N` to change that. With `args.sample`, it reads the sample meetings instead; every ingest step works this way. cognee's part is one call: `cognee.remember`, into the dataset `personalized_email` with `node_set=["meetings"]`. [`remember`](/core-concepts/main-operations/remember) turns text into a knowledge graph of people, decisions and dates. A [*dataset*](/core-concepts/further-concepts/datasets) is the named memory everything goes into. A [*node set*](/core-concepts/further-concepts/node-sets) is a tag on what you remember, so you can later recall from that part alone.

### Step 3: Remember Your Inbox and Sent Mail

Source: [`scripts/ingest_email.py`](https://github.com/topoteretes/cognee/blob/dev/examples/cookbooks/personalized_email/scripts/ingest_email.py)

This step saves your newest emails: the inbox for facts, your sent mail as a sample of how you write. It takes the newest 50 inbox emails and the newest 50 sent emails, not your whole mailbox. Pass `--emails N` to change how many.

```python theme={null}
await ingest_email(args.emails, args.sample)
```

The script calls `cognee.remember` once per label, with cognee's [Gmail connector](/guides/gmail-ingestion), `gmail_source`, as the input. Inbox mail gets the node set `inbox` and sent mail gets `sent_mail`. That split matters in the next step: the agent can ask for your own writing without mixing in other people's. `write_disposition="merge"` with `primary_key="id"` merges emails by message id, so a rerun does not store the same email twice.

### Step 4: Draft the Reply

Source: [`scripts/draft.py`](https://github.com/topoteretes/cognee/blob/dev/examples/cookbooks/personalized_email/scripts/draft.py)

This step reads the newest email in your inbox and prints the reply you would write. On the sample, it writes as Mira.

```python theme={null}
await draft(args.sample)
```

The agent is two [`cognee.recall`](/core-concepts/main-operations/recall) calls. The first uses `query_type=SearchType.CHUNKS` with `node_name=["sent_mail"]`. It returns three of your own emails as raw text, so the draft can copy your exact greeting and sign-off. The second uses `HYBRID_COMPLETION`, which gives the LLM the matching source passages and the graph around them in one call, so dates and prices are copied from the text. It gets the new email, your three emails, and `DRAFT_PROMPT`: answer every question from memory, never invent a date or price, and if you owe the sender something, say plainly whether it was sent.

## Make It Yours

* **Write in a different voice.** Edit `DRAFT_PROMPT` in `scripts/draft.py`: keep replies to three sentences, always propose a call, or answer in the sender's language.
* **Add your pricing sheet.** Write one more ingest script that calls `cognee.remember` on a folder of documents with its own node set, and add it to `run()`. The draft then answers from your real price list. See [Remember](/core-concepts/main-operations/remember) for the inputs it accepts.
* **Build a meeting-prep agent.** Keep steps 2 and 3 as they are and replace the draft with one `HYBRID_COMPLETION` recall: "What did I promise Priya Shah, and what is still open?" Same memory, a different application.
* **Look at your memory before trusting it.** Recall with `node_name=["meetings"]` to see only what came from calls. [NodeSet Grouping](/guides/nodeset-grouping) shows how scoping works.

## Clean Up

```bash theme={null}
uv run cognee-cli forget --dataset personalized_email
```

To start over completely, also delete `sample/` and `token.json` in the cookbook folder.

<Columns cols={2}>
  <Card title="NodeSet Grouping" icon="layers" href="/guides/nodeset-grouping">
    Tag memories by source and recall from one part at a time.
  </Card>

  <Card title="Gmail Ingestion" icon="mail" href="/guides/gmail-ingestion">
    How the Gmail connector syncs your mail incrementally.
  </Card>

  <Card title="Follow-Up Agent" icon="list-checks" href="/cookbooks/follow-up-agent">
    Build another one: next steps from your latest call, posted to Slack.
  </Card>

  <Card title="Self-Hosted AI Companion" icon="notebook-pen" href="/cookbooks/self-hosted-companion">
    Build another one: a chat companion that remembers your notes.
  </Card>
</Columns>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.