Email API
The BKR Email API (bkr-email-api) is a FastAPI service that gives the Mansa agents safe, scoped access to the BKR Capital shared mailbox (pipeline@bkrcapital.ca). It wraps Microsoft Graph API behind a clean REST interface with API key authentication.
| Layer | Technology |
|---|---|
| Framework | FastAPI (Python 3.13+) |
| Auth | Azure AD / MSAL (Microsoft Authentication Library) |
| HTTP client | httpx (async) |
| Data validation | Pydantic v2 |
| Deployment | Azure Container Apps |
Authentication
Section titled “Authentication”The API uses a two-tier API key system via the X-API-Key request header:
- Master key (
API_KEY): full access to all endpoints - Scoped keys (
API_KEYS): restricted by scope
Available scopes:
| Scope | Grants access to |
|---|---|
send:email |
POST /send |
download:attachment |
GET /emails/{id}/attachments/{attachment_id} |
API Reference
Section titled “API Reference”| Method | Path | Description |
|---|---|---|
GET |
/emails |
List inbox emails. Supports unread_only, past_day, include_labeled, and pagination via next_link |
GET |
/emails/by-category/{category} |
List emails with a specific category label |
GET |
/emails/search |
Full-text search across the mailbox (?q=text) |
GET |
/emails/{message_id} |
Get full email details including body, recipients, and attachments |
POST |
/emails/{message_id}/read |
Mark an email as read |
GET |
/emails/{message_id}/attachments/{attachment_id} |
Download an attachment (requires download:attachment scope) |
Labels
Section titled “Labels”| Method | Path | Description |
|---|---|---|
POST |
/emails/{message_id}/label |
Apply a category label (ai-processed or ai-misc) |
Drafts
Section titled “Drafts”| Method | Path | Description |
|---|---|---|
GET |
/drafts |
List drafts in the Drafts folder |
POST |
/drafts/reply |
Create a reply-all draft for a specific message |
| Method | Path | Description |
|---|---|---|
POST |
/send |
Send an email (requires send:email scope) |
System
Section titled “System”| Method | Path | Description |
|---|---|---|
GET |
/health |
Health check that validates required settings are present |
Key Design Decisions
Section titled “Key Design Decisions”AI Processing Labels
Section titled “AI Processing Labels”Emails are categorised with Outlook categories to track processing state:
ai-processed: the agent handled this email (created/updated Attio records; drafted a pitch deck request if none was included)ai-misc: the agent saw this email but it was not a relevant lead
By default, GET /emails excludes emails that already carry either label. Set include_labeled=true to override. This ensures agents don’t reprocess the same email across runs.
HTML-to-Markdown Conversion
Section titled “HTML-to-Markdown Conversion”Email bodies are stored as HTML in Outlook. The API converts them to Markdown before returning them to agents, because Markdown is far more token-efficient in a Claude context window. It strips layout-only tables (common in HTML email templates) and falls back to the original HTML if the conversion yields nothing.
Send Restrictions
Section titled “Send Restrictions”Recipients are restricted to @bkrcapital.ca addresses. This prevents the agent from accidentally sending emails to founders or external parties from the send endpoint (founder reply drafts go through the draft flow instead).
Auto-CC
Section titled “Auto-CC”Every sent email automatically CCs pipeline@bkrcapital.ca so the full team can see what was sent. A DEBUG_ADDRESS env var can CC a second address during testing.
Pagination
Section titled “Pagination”All list endpoints support top (1–100, default 25) and next_link pagination. The next_link value is an OData cursor returned by Microsoft Graph. When set, other query parameters are ignored and the cursor drives the next page.
Deployment
Section titled “Deployment”The API runs on Azure Container Apps in BKR Capital’s Azure account.
App: mansa-email-apiRegion: Canada Central (canadacentral)Deployment is done manually using the scripts in bkr-email-api/scripts/. Environment variables are managed as Container Apps secrets. See .env.example for the full list of required variables.
The app can be accessed directly in the Azure Portal.
Testing
Section titled “Testing”- 40+ unit tests using pytest + respx (async httpx mocking)
- End-to-end suite targeting
ai-test-labelled emails in the real mailbox (requires live Azure credentials)
# Unit testspytest tests/ -v
# E2E tests (requires .env with live credentials)pytest tests/e2e/ -v -m e2e