Register your interest: Tag @Cody, get an agent
BlogResources

How to turn emails into Notion database rows reliably

Parsing an email is guesswork. Structured intake, matching on something stable, and what to do when the message does not contain what the database requires.

Amman VediAmman Vedi11 min read

Summarize with AI

How to turn emails into Notion database rows reliably
On this page

Turning emails into database rows is a reasonable thing to want and an unreliable thing to build, because an email is unstructured text written by somebody who was not thinking about your database.

Most of the difficulty is not technical. It is that the information your properties require is frequently not in the message, and an automation that guesses at it produces rows that look complete and are wrong — which is worse than rows that are visibly incomplete.

What we'll cover

Parsing email is guesswork

Formats vary by sender, and the same person writes differently on a phone.

Forwarded messages nest, and the interesting content is inside a quoted block with headers that are not the real headers.

Signatures look like content. A phone number in a signature is not the phone number for this request.

Reply chains accumulate, so the newest message sits above a history that also contains dates, names, and numbers a parser will happily pick up.

Automated senders change their format without notice, which breaks extraction silently.

Attachments carry the actual information in a substantial share of cases, which is a different problem again.

So treat extraction as unreliable by default, and design for the cases where it fails rather than assuming a good parse.

Structured intake beats extraction

The point worth making before any of the mechanics.

If you control how people send it, use a form. A form with five fields produces perfect rows and requires no parsing at all.

A mailto link with a template is the middle ground where a form is not practical — it prefills a structure the sender edits.

For automated senders you control, change the sending format rather than parsing it, which is usually a five-minute change at the source.

Reserve parsing for what you genuinely cannot control — external senders, existing processes, forwarded correspondence.

The effort spent on a robust parser is frequently larger than the effort of changing the intake, and the parser needs maintaining forever.

Say which situation you are in before building, because the answer changes the whole approach.

Designing the database for this

Use property types that accept what you will have. A required select that email can rarely determine produces rows you cannot create.

Make properties optional where extraction may fail, and report the gaps rather than blocking.

Add a status property with a triage state, so incomplete rows are visibly waiting rather than mixed in with complete ones.

Add a source property recording where the row came from, since a database fed from several places needs to distinguish them.

Store the message identifier in a property, which is what makes the automation idempotent and lets you link back.

Keep the property set small. Every property the email cannot fill is a property somebody has to fill afterwards, and they will not.

Building it with CodeWords

CodeWords connects to more than 3,000 integrations, so the mailbox, the database, and any notification can run as one automation.

  1. Open CodeWords and start a new automation.
  2. Describe what should happen in plain language to Cody, the automation builder: which mailbox, which database, and what each property should contain.
  3. Authorize the connections, then share the target database with the Notion integration — access is per page and this manual step is why most first Notion automations find nothing.
  4. Describe the exceptions: a message missing a required value, a duplicate, a reply to something already captured.
  5. Send test messages in the shapes you actually receive, including a forwarded one, before pointing it at a live mailbox.

You describe the outcome; Cody builds it, connects it, and deploys it. The free plan covers light use, with Pro at $39 per month and Business at $100 per month as usage grows; details are on the pricing page.

What to do with the message body

Keep the original. Whatever you extract, the full text should be in the page so nothing is lost to a bad parse.

Put it in the page body, not in a property, since properties are for structured values and a long text property is unusable in every view.

Strip the quoted history where you can, or put it behind a toggle, since a page that is ninety per cent reply chain is a page nobody reads.

Link to the original message where your mail system supports a stable link, which is more reliable than any copy.

Handle attachments deliberately — upload them, link them, or note that they exist — rather than silently dropping them, which is the default and loses information people assume was captured.

Note the sender and the date as properties, since those are the two things every view will want to filter on.

Duplicates and threads

The same email arrives twice — retried delivery, a forward, somebody copying you separately.

Key on the message identifier rather than on the subject, which is unstable and shared across a thread.

Decide about replies. A reply to a captured message can create a new row, update the existing one, or append to its page — and each is right for a different use.

Appending is usually right for a request that develops, and a new row is right where each message is genuinely a separate item.

Report the duplicate rather than silently skipping, so somebody can see the automation made a judgement.

Watch for the loop. An automation that sends a notification which lands in the same mailbox it monitors is a recognisable and expensive mistake.

When the message is missing something

The case that matters most and gets designed last.

Create the row anyway, in a triage state, with the gaps visible. A missing row is worse than an incomplete one, because nobody knows it should exist.

Never invent a value. A plausible guess at a category or a date is acted upon, and a blank is questioned.

Note what was missing, in a property or a comment, so whoever completes it knows what to look for.

Reply to the sender asking for what is needed, immediately, while they still have the context — which is far more effective than asking three days later.

Report the pattern. If half of incoming messages lack the same field, the intake needs changing rather than the parser.

Make triage someone's job. A triage state nobody sweeps is a queue, which is the failure this whole design was avoiding.

Which mailbox, and who can read it

A detail settled early or regretted later.

Use a shared mailbox, not somebody's personal one, so the automation survives that person leaving and nobody's private mail is in scope.

Scope the access narrowly — one mailbox or one label, read-only where the automation only reads.

Be aware of what else arrives there. A general enquiries address receives things nobody intended to put in a database, including occasionally sensitive material.

Filter before capturing rather than capturing everything and sorting afterwards, since a row created is a copy made.

Consider who can see the database. Notion sharing is separate from mailbox permissions, and an automation can quietly widen who sees correspondence.

Have a deletion route. A message deleted from the mailbox does not disappear from Notion, which matters when somebody asks for their data to be removed.

Making it survive

Make it idempotent, keyed on the message identifier.

Share the database with the integration, and check that access has not been removed — it is the commonest cause of a Notion automation silently doing nothing.

Read property definitions rather than hard-coding select options, since options change and writing one that no longer exists fails.

Pace requests, as Notion's rate limits are modest and a busy mailbox can exceed them.

Report the outcome. Messages processed, rows created, rows in triage, duplicates skipped, and anything that failed.

Limits worth knowing about

Notion access is per page, so the integration sees only what has been shared with it — the usual reason nothing appears.

Rate limits are modest, roughly a few requests per second, which matters for bulk imports.

Property types are strict, and writing a value of the wrong shape fails rather than coercing.

Page content is a block tree, so a long email body becomes several blocks and formatting will not survive exactly.

Notion is not a ticketing system. If the rows need assignment, SLAs, and status workflows, a tool built for that will do it better and this automation is a workaround.

What to build first

Capture with the full message body preserved and a triage status, creating a row for every message regardless of what could be extracted. It guarantees nothing is lost, it makes the gaps visible, and the triage queue's contents tell you exactly which fields to ask for at intake instead of parsing.

Two habits make the difference. Never invent a missing value — a blank gets questioned and a plausible guess gets acted on. And reply to the sender asking for what was missing at the moment it arrives, since that is both far more effective than asking later and the fastest route to discovering that the intake should be a form.

Frequently asked questions

Why is parsing emails unreliable?

Because formats vary by sender and device, forwarded messages nest, signatures look like content, reply chains accumulate text a parser will pick up, and automated senders change format without notice. The failures are silent.

What is the alternative?

Structured intake. A form with five fields produces perfect rows and needs no parsing, and for automated senders you control, changing the sending format is usually a five-minute change at the source.

What should happen when a field cannot be extracted?

Create the row anyway, in a triage state, with the gap visible and noted — and never invent a value. A missing row is worse than an incomplete one because nobody knows it should exist.

Where should the email body go?

In the page body rather than a property, with the quoted history stripped or behind a toggle. Properties are for structured values, and a long text property is unusable in every view.

How do I avoid duplicate rows?

Key on the message identifier, not the subject, which is unstable and shared across a thread. Decide explicitly whether replies create a row, update one, or append to its page.

Why does my Notion automation create nothing?

The database has not been shared with the integration. Access is granted per page inside Notion, it is a manual step, and it is the reason nearly every first Notion automation finds nothing.

Should this be in Notion at all?

If the rows need assignment, status workflows, and SLAs, a purpose-built tool will do it better. Notion suits lightweight tracking, and it is worth being honest about which of the two you actually have.

Which mailbox should the automation watch?

A shared one, scoped to a single label where possible and read-only if it only reads. A personal mailbox puts private correspondence in scope and stops working when that person leaves.

Does deleting the email remove the row?

No. The Notion row is a separate copy with separate sharing, which matters when somebody asks for their data to be removed — the deletion has to reach both, and nothing does that automatically.

Get started today

Your first workflow is free to build.

Describe what you need. Cody handles the build, the connections, and the deployment.