# How Macro Creates Tasks from Emails with Bidirectional Linking

> Learn how Macro automatically creates tasks from emails using bidirectional linking to connect tasks and source messages. Effortlessly manage your workflow.

- Repository: [Macro/macro](https://github.com/macro-inc/macro)
- Tags: how-to-guide
- Published: 2026-08-18

---

**Macro creates tasks from emails by parsing inbound messages for task cues, persisting them as documents with subtype "task", and establishing symmetric Link records in the database that enable querying from either the email or task direction.**

The macro-inc/macro codebase implements a robust pipeline that transforms incoming emails into actionable tasks while maintaining persistent bidirectional relationships between the source message and the derived task. This architecture ensures that users can navigate seamlessly from an email to its associated task and vice versa through a symmetric linking mechanism implemented in Rust.

## Email Ingestion and Task Detection

When an inbound email arrives, the **email service** handles the initial parsing and persists the message as a standard email entity within the system. The [`services/email_service/src/api/swagger.rs`](https://github.com/macro-inc/macro/blob/main/services/email_service/src/api/swagger.rs) file defines the API contract that registers the endpoints triggering this processing, while [`packages/sdk/specs/email.json`](https://github.com/macro-inc/macro/blob/main/packages/sdk/specs/email.json) specifies the underlying data structure for email handling.

Simultaneously, the **search-processing service** analyzes the email content for task creation signals. This includes explicit commands such as "/task", explicit task-creation intents, or automatically detected action items within the message body.

### Building the Task Document

Upon detecting a task cue, the system constructs a specialized document in [`services/search_processing_service/src/process/document/raw_document.rs`](https://github.com/macro-inc/macro/blob/main/services/search_processing_service/src/process/document/raw_document.rs). The service creates a **Document** struct flagged with `sub_type: Some("task".to_string())`, which distinguishes it from standard documents and enables task-specific UI rendering.

```rust
let task_doc = Document {
    title: extracted_title,
    sub_type: Some("task".to_string()),
    // …other fields…
};
let task_id = document_db.insert(task_doc).await?;

```

This document is inserted into **MacroDB** as a regular document entry, but the task subtype flag ensures it appears in task-specific views and workflows.

## Establishing Bidirectional Links

To maintain the relationship between the originating email and the newly created task, the **email link manager** creates a symmetric **Link** record in [`services/email_service/src/pubsub/link_manager/process.rs`](https://github.com/macro-inc/macro/blob/main/services/email_service/src/pubsub/link_manager/process.rs). This record stores both the source entity type (`email`) and target entity type (`task`) along with their respective identifiers.

The link table architecture is inherently symmetric, meaning a single row enables traversal in both directions. Queries can resolve email-to-task relationships or task-to-email relationships using the same underlying record.

```rust
let link = Link {
    source_entity_type: EntityType::Email,
    source_entity_id: email_id,
    target_entity_type: EntityType::Task,
    target_entity_id: task_id,
};
link_manager.create(link).await?;

```

### Querying Related Entities

Because the link structure is symmetric, the UI can efficiently retrieve related entities from either direction. When viewing an email, the system queries for associated tasks; when viewing a task, it retrieves the originating email.

```rust
let related = link_manager
    .find_by_source(EntityType::Email, email_id)
    .await?; // returns the task ID

```

## Removing Email-Task Associations

The link manager also handles the deletion of associations when tasks are unlinked from their source emails. The error handling logic at line 366 of [`services/email_service/src/pubsub/link_manager/process.rs`](https://github.com/macro-inc/macro/blob/main/services/email_service/src/pubsub/link_manager/process.rs) demonstrates the background task responsible for removing these relationships.

```rust
link_manager
    .delete(link_id)
    .await
    .context("Failed to delete link in background task")?;

```

## Summary

- **Email ingestion** triggers the pipeline through the email service, which parses and stores messages according to the API contract defined in [`packages/sdk/specs/email.json`](https://github.com/macro-inc/macro/blob/main/packages/sdk/specs/email.json).
- **Task detection** occurs in the search-processing service, which scans for "/task" commands and action items before creating documents with subtype "task" in [`raw_document.rs`](https://github.com/macro-inc/macro/blob/main/raw_document.rs).
- **Bidirectional linking** is implemented through symmetric Link records in the email link manager, enabling queries from either email-to-task or task-to-email directions.
- **Link removal** is handled as a background task in [`services/email_service/src/pubsub/link_manager/process.rs`](https://github.com/macro-inc/macro/blob/main/services/email_service/src/pubsub/link_manager/process.rs), ensuring clean disassociation when needed.

## Frequently Asked Questions

### How does Macro detect when to create a task from an email?

The search-processing service examines incoming email content for specific cues such as "/task" commands, explicit task-creation intents, or automatically detected action items. When found, it instantiates a Document with `sub_type: "task"` and persists it to MacroDB.

### What database structure enables bidirectional linking between emails and tasks?

The system uses a symmetric Link table that stores `source_entity_type`, `source_entity_id`, `target_entity_type`, and `target_entity_id`. Because the architecture treats the relationship as symmetric, queries can traverse from email to task or task to email using the same underlying record without requiring duplicate entries.

### Can the link between an email and a task be removed programmatically?

Yes, the email link manager provides deletion capabilities through background tasks defined in [`services/email_service/src/pubsub/link_manager/process.rs`](https://github.com/macro-inc/macro/blob/main/services/email_service/src/pubsub/link_manager/process.rs). The error handling at line 366 specifically manages the cleanup of link records when associations are removed.

### Which services are involved in the email-to-task pipeline?

Three primary services collaborate: the email service handles ingestion and API endpoint registration, the search-processing service performs content analysis and task document creation, and the email link manager maintains the bidirectional associations between entities.