All Startup Ideas

Email to Todo Converter

AI extracts actionable tasks from emails, routes to Todoist/Notion/Linear. Flat pricing, natural priority detection. Weekend MVP guide + prompts.

The average knowledge worker receives 121 emails per day (Radicati Group 2024). Roughly 15–20 of those require specific action — "can you review this doc by Thursday," "we need the deck before the Monday exec meeting," "customer X wants the refund processed today." The actions are buried inside three paragraphs of context, embedded as a single sentence in the middle of a reply-all thread, or listed as a bulleted dump at the bottom of a meeting recap. Todoist has an email-forward feature. So does Things, TickTick, Omnifocus, Microsoft To Do. They all work the same way: forward an email, it becomes a task with the subject as the title and the body as the description. No due date extraction. No priority inference. No detection of "this email has three asks, not one." The user still has to read the task, extract what it actually means, set a date, and move on.

Built for Developers, Solo Founders, Side Hustlers, Designers.

Suggested stack: Resend Inbound Email, Next.js 14 App Router, Claude Haiku 4.5, Supabase, Destination integrations (OAuth), Stripe Billing + Upstash Rate Limit. Weekend scope: about 8 hours.

The Problem

The average knowledge worker receives 121 emails per day (Radicati Group 2024). Roughly 15–20 of those require specific action — "can you review this doc by Thursday," "we need…

The Solution

User signs up, gets a unique forwarding address like `inbox.jeff.a8b2@task.product.com`. Forwards any email there. Claude parses: identifies distinct action items, detects due…

Market Research

Todoist has 30M+ users, 5M+ paid (company stats). Notion crossed 30M users. Linear serves 10K+ SaaS teams. Each has an email-in feature with weak parsing — every user of those…

Competitive Landscape

Todoist / Things / TickTick email-in — Native forwarding addresses. Subject becomes task title, body becomes description. Zero parsing. No due-date extraction, no priority…

Business Model

Free ($0) — 10 emails/mo, 1 destination, digest-only output

Recommended Tech Stack

Resend Inbound Email — Configure `inbox.*.user@task.product.com` catch-all routing to webhook. Resend forwards parsed MIME (subject, from, text, html, attachments) as JSON to…

AI Prompts to Build This

Copy these build prompts into Claude, Cursor, or your AI coding tool. Create a free account to unlock the full research behind them.

  1. 1. Inbound Email + User Addressing

    Create a Next.js 14 App Router app with Resend Inbound email routing.
    
    DNS setup:
    - Register task.product.com as a Resend domain.
    - Add MX records pointing to Resend inbound servers.
    - Configure catch-all routing: all inbox.*@task.product.com → https://product.com/api/inbound webhook.
    
    Schema:
    - users(id, email, inbox_slug, plan, stripe_customer_id, created_at)
    - destinations(id, user_id, type ENUM[todoist,notion,linear,things,email_digest], oauth_access_token_encrypted, oauth_refresh_token_encrypted, config JSONB)
    - emails_processed(id, user_id, from_address, subject, received_at, llm_tokens_used, status ENUM[pending,processed,failed])
    - tasks_extracted(id, email_id, title, due_date, priority, owner, context_snippet, pushed_to_destinations JSONB)
    - usage_monthly(id, user_id, month, emails_processed_count, llm_cost_cents)
    
    On user signup:
    - Generate inbox_slug as hex(random(3)) + '.' + slugify(first_name) + hex(random(2)) → e.g. 'a8b2.jeff.c4d1'. Collision check; retry.
    - Store on users.inbox_slug. User's forwarding address is {inbox_slug}@task.product.com.
    
    /api/inbound endpoint:
    - Verify Resend signature header.
    - Parse payload: from, to (extract inbox_slug), subject, text, html, attachments.
    - Find user by inbox_slug. If not found, 404 (prevents random address spam).
    - Enforce monthly rate limit via Upstash: if over, reply to sender with friendly upgrade message.
    - Enqueue processing job (Vercel Cron or QStash).
    
    Return 200 fast (< 5s); do LLM work async.
  2. 2. AI Task Extraction

    Implement the email-to-task extraction with Claude Haiku 4.5.
    
    Prompt construction:
    - User context: their timezone, default priority preference, typical working hours.
    - Email: from, subject, body (strip signatures, HTML tags, quoted thread history).
    - Today's date in ISO.
    
    System prompt:
    "You extract actionable tasks from a single email. Return strict JSON matching this schema:
    {
     thread_summary: 'one sentence of what the email is about',
     tasks: [
     {
     title: 'imperative verb + object, max 80 chars',
     due_date: 'ISO date or null, inferred from phrases like by Friday, EOD, next Monday',
     priority: 'low' | 'medium' | 'high' based on urgency language and explicit markers,
     owner: 'the person the task is for — null if ambiguous, or the user email if clearly a personal ask',
     context_snippet: '15-30 word quote from the email that establishes the ask'
     }
     ],
     sender_urgency: 'low' | 'medium' | 'high' — the overall tone
    }
    
    Rules:
    - Only include tasks that are real action items. Informational content ('FYI') is NOT a task.
    - If the email has 0 tasks, return tasks: [].
    - 'by Friday' relative to today's date. 'next week' = Monday through Sunday of next calendar week.
    - Priority 'high' if words like 'urgent', 'asap', 'blocker', 'production down' appear. 'low' if casual/FYI language. Default 'medium'.
    - Never hallucinate due dates. If unclear, due_date: null.
    
    Today is {today}. User timezone: {tz}."
    
    Call Claude via Anthropic SDK with response_format: {type: 'json_schema'}. Validate structure; if malformed, log and retry once with simpler prompt. On success, write tasks_extracted rows.
    
    Fan out to destinations: call each destination adapter's pushTasks(tasks). If destination fails (e.g., OAuth token expired), log to emails_processed.status = 'failed_destination' and email user.
  3. 3. Destination Adapters (Todoist + Notion)

    Build destination adapters with a common interface: export async function pushTasks(tasks: Task[], config: Config): Promise.
    
    Todoist adapter (destinations/todoist.ts):
    - OAuth flow: user clicks 'Connect Todoist', redirect to https://todoist.com/oauth/authorize?client_id=X&scope=data:read_write&state=user_id. Callback at /api/destinations/todoist/callback exchanges code for token.
    - Store access_token encrypted + project_id where tasks should go (default Inbox).
    - pushTasks: for each task, POST to https://api.todoist.com/rest/v2/tasks with body:
     {
     content: task.title,
     description: task.context_snippet,
     due_date: task.due_date,
     priority: task.priority === 'high' ? 4 : task.priority === 'medium' ? 3 : 2,
     project_id: config.project_id
     }
    - Handle rate limit: 450 tasks/15min. Batch with Promise.all, max 5 concurrent.
    
    Notion adapter (destinations/notion.ts):
    - OAuth flow: user authorizes a Notion integration scoped to a specific database.
    - Store access_token + database_id.
    - pushTasks: for each task, POST to https://api.notion.com/v1/pages:
     {
     parent: { database_id: config.database_id },
     properties: {
     Name: { title: [{ text: { content: task.title } }] },
     'Due Date': task.due_date ? { date: { start: task.due_date } } : null,
     Priority: { select: { name: task.priority } },
     Context: { rich_text: [{ text: { content: task.context_snippet } }] }
     }
     }
    - User must pre-create database with these property names; show schema doc on connect.
    
    Digest email adapter (destinations/email_digest.ts):
    - Collect tasks across the day; send one digest email at user-configured time (default 6pm local).
    - React Email template with checkboxes, priorities color-coded, tappable add-to-calendar links.
    
    Error handling: on 401, mark OAuth token as expired, email user to reconnect. Never push tasks to a stale destination.