Skip to main content

InboundEmail Data Model

Schema

Defined in src/modules/inbound_emails/models/inbound-email.ts using Medusa DML:

import { model } from "@medusajs/framework/utils"

const InboundEmail = model.define("inbound_email", {
id: model.id({ prefix: "inb_email" }).primaryKey(),
imap_uid: model.text(),
message_id: model.text().nullable(),
from_address: model.text().searchable(),
to_addresses: model.json(),
subject: model.text().searchable(),
html_body: model.text(),
text_body: model.text().nullable(),
folder: model.text(),
received_at: model.dateTime(),
status: model.enum(["received", "action_pending", "processed", "ignored"]).default("received"),
action_type: model.text().nullable(),
action_result: model.json().nullable(),
extracted_data: model.json().nullable(),
error_message: model.text().nullable(),
metadata: model.json().nullable(),
})

Field Reference

FieldTypeNullableDefaultSearchableDescription
idstringNoAuto-generated (inb_email_*)Primary key with custom prefix
imap_uidtextNoIMAP message UID, used for deduplication
message_idtextYesRFC 2822 Message-ID header
from_addresstextNoYesSender email address
to_addressesjsonNoArray of recipient addresses
subjecttextNoYesEmail subject line
html_bodytextNoFull HTML body of the email
text_bodytextYesPlain text version (if available)
foldertextNoIMAP folder the email was fetched from
received_atdatetimeNoDate from the email header
statusenumNoreceivedProcessing status
action_typetextYesRegistered action type (e.g. create_inventory_order)
action_resultjsonYesResult data from action execution
extracted_datajsonYesParsed data from the extraction step
error_messagetextYesLast error message if action failed
metadatajsonYesArbitrary metadata

Status Enum

ValueDescription
receivedEmail fetched and stored, no action taken
action_pendingData extracted, waiting for admin to execute or ignore
processedAction executed successfully
ignoredAdmin marked as not needing action

Status Transitions

received ──(POST extract)──> action_pending ──(POST execute)──> processed
│ │
└────(POST ignore)──> ignored <┘

Service Methods

The module service extends MedusaService({ InboundEmail }), which auto-generates these methods:

MethodDescription
createInboundEmails(data)Create one or more records
retrieveInboundEmail(id)Get a single record by ID
listInboundEmails(filters, config)List records with filters
listAndCountInboundEmails(filters, config)List + total count
updateInboundEmails(id, data)Update a record
deleteInboundEmails(id)Soft-delete a record

Example: Creating a Record

const service = container.resolve("inbound_emails")

const email = await service.createInboundEmails({
imap_uid: "1234",
message_id: "<[email protected]>",
from_address: "[email protected]",
to_addresses: ["[email protected]"],
subject: "Order Confirmation #12345",
html_body: "<html>...</html>",
text_body: "Order confirmed...",
folder: "INBOX",
received_at: new Date(),
status: "received",
})
// email.id => "inb_email_01ABC..."

Example: Listing with Filters

const [emails, count] = await service.listAndCountInboundEmails(
{ status: "received", from_address: "[email protected]" },
{ skip: 0, take: 20, order: { received_at: "DESC" } }
)

A many-to-many link exists between InboundEmail and InventoryOrder:

// src/links/inbound-email-inventory-order.ts
import { defineLink } from "@medusajs/framework/utils"
import InboundEmailModule from "../modules/inbound_emails"
import InventoryOrdersModule from "../modules/inventory_orders"

export default defineLink(
{ linkable: InboundEmailModule.linkable.inboundEmail, isList: true },
{ linkable: InventoryOrdersModule.linkable.inventoryOrders, isList: true }
)

This allows querying related records via the Medusa link system.