How to Automate Email Responses with n8n and Ollama (Free, Self-Hosted)

Published March 24, 2026 · 18 min read · Beginner-friendly

Your inbox is a time sink. The average professional spends 28% of their workday reading and responding to email — that is roughly 2.5 hours every single day. Most of those emails fall into predictable categories: support questions, sales inquiries, scheduling requests, and spam. What if an AI running entirely on your own machine could handle the triage and draft responses for you?

In this tutorial, you will build a complete email auto-response system using n8n (open-source workflow automation) and Ollama (local AI model runner). No API keys, no monthly fees, no data leaving your network. The entire pipeline — from reading incoming mail to drafting context-aware replies — runs on your hardware for free.

What you will build: An automated pipeline that checks your inbox every 5 minutes, classifies each email by category and urgency, filters out spam, and drafts personalized replies — all powered by a local Llama 3 model through Ollama.

Table of Contents

Why Automate Email with Local AI?

You could use OpenAI or Claude for email automation, but there are strong reasons to keep this workflow self-hosted:

System Architecture Overview

Before diving into the build, here is how all the pieces fit together:

IMAP Inbox
    |
    v
[n8n: Email Trigger] -- polls every 5 minutes
    |
    v
[n8n: HTTP Request to Ollama] -- classifies email
    |
    v
[n8n: Code Node] -- parses AI JSON response
    |
    v
[n8n: Switch Node] -- routes by category
    |
    +--> support --> [Ollama: draft support reply] --> [Send/Save draft]
    +--> sales   --> [Ollama: draft sales reply]   --> [Send/Save draft]
    +--> meeting --> [Ollama: draft scheduling reply] --> [Send/Save draft]
    +--> spam    --> [Archive / Delete]
    +--> other   --> [Forward to team / Flag for review]

The workflow has two AI calls per email: one for classification and one for drafting the reply. On an 8B parameter model, each call takes 10-30 seconds depending on your hardware. That means processing a batch of 20 emails takes roughly 5-10 minutes — well within the polling interval.

Prerequisites and Setup

If you already have n8n and Ollama running, skip ahead to Step 1. Otherwise, here is the quick setup.

1 Install Ollama and pull a model

# Install Ollama (Linux/macOS)
curl -fsSL https://ollama.ai/install.sh | sh

# Pull the recommended model
ollama pull llama3:8b

# Verify it is running
curl http://localhost:11434/api/tags

You should see a JSON response listing your installed models. If you get a connection error, run ollama serve in a separate terminal.

2 Install n8n via Docker

docker run -d --name n8n \
  -p 5678:5678 \
  -v n8n_data:/home/node/.n8n \
  --add-host=host.docker.internal:host-gateway \
  n8nio/n8n

The --add-host flag is critical — it lets the Docker container reach Ollama on your host machine. Open http://localhost:5678 and create your account.

3 Test the connection

In n8n, create a new workflow. Add an HTTP Request node with URL http://host.docker.internal:11434/api/tags and method GET. Execute it. If you see your model list, the connection is working.

Step 1: Connect n8n to Your Inbox (IMAP)

Add an IMAP Email trigger node to your workflow. This node polls your inbox at a set interval and passes new emails into the pipeline.

IMAP Configuration

Mailbox: INBOX
Credentials:
  Host: imap.gmail.com (or your provider)
  Port: 993
  User: your-email@gmail.com
  Password: your-app-password (NOT your regular password)
  SSL/TLS: true

Options:
  Poll interval: 5 minutes
  Mark as read: true
  Download attachments: false
Gmail users: You need an App Password, not your regular Google password. Go to Google Account → Security → 2-Step Verification → App Passwords and generate one for "Mail." If you use Microsoft 365, enable IMAP in Exchange admin and use an app password there as well.

For testing, you can use a Manual Trigger followed by a Set node to simulate incoming emails:

{
  "from": "sarah@clientcorp.com",
  "subject": "Urgent: Production server down",
  "body": "Hi team, our production environment went down about 30 minutes ago. Customers are reporting 500 errors across all API endpoints. We need immediate assistance. This is blocking our launch scheduled for tomorrow morning. Please escalate ASAP.",
  "date": "2026-03-24T14:30:00Z"
}

Step 2: Classify Emails with Ollama

This is where the AI magic happens. Add an HTTP Request node that sends each email to Ollama for classification.

The Classification Prompt

The quality of your classification depends almost entirely on the prompt. Here is one that has been tested across thousands of emails:

URL: http://host.docker.internal:11434/api/generate
Method: POST
Body Type: JSON
Body:
{
  "model": "llama3:8b",
  "prompt": "You are an email classification assistant. Analyze the following email and return a JSON object with your analysis.\n\nCategories (pick exactly one):\n- support: Technical issues, bugs, account problems, how-to questions\n- sales: Pricing inquiries, purchase interest, demo requests, partnership proposals\n- meeting: Scheduling requests, calendar invites, availability questions\n- feedback: Product feedback, feature requests, complaints, reviews\n- newsletter: Marketing emails, newsletters, promotional content\n- spam: Unsolicited ads, phishing attempts, irrelevant mass mail\n- internal: Team communication, project updates, HR matters\n\nUrgency levels:\n- critical: System down, data loss, security incident, deadline today\n- high: Blocking issue, important client, time-sensitive (24-48h)\n- medium: Standard request, normal business timeline\n- low: FYI, newsletter, non-urgent feedback\n\nSentiment:\n- positive, neutral, negative, angry\n\nEmail:\nFrom: {{ $json.from }}\nSubject: {{ $json.subject }}\nBody: {{ $json.body }}\n\nReturn ONLY valid JSON, no other text:\n{\"category\": \"...\", \"urgency\": \"...\", \"sentiment\": \"...\", \"summary\": \"one sentence summary\", \"requires_reply\": true/false}",
  "stream": false,
  "options": {
    "temperature": 0.1,
    "num_predict": 200
  }
}

Key decisions in this prompt:

Parse the AI Response

Add a Code node after the HTTP Request to extract the JSON from Ollama's response:

// Parse the classification from Ollama's response
const aiResponse = $input.first().json.response;

// Extract JSON from the response (handles cases where the model
// adds extra text before/after the JSON)
const jsonMatch = aiResponse.match(/\{[\s\S]*\}/);

if (!jsonMatch) {
  // Fallback: if AI didn't return valid JSON, flag for manual review
  return [{
    json: {
      category: 'other',
      urgency: 'medium',
      sentiment: 'neutral',
      summary: 'Could not auto-classify',
      requires_reply: false,
      parse_error: true,
      original_email: $('Set').first().json
    }
  }];
}

const classification = JSON.parse(jsonMatch[0]);

// Merge classification with original email data
return [{
  json: {
    ...classification,
    original_email: $('Set').first().json  // Replace 'Set' with your trigger node name
  }
}];
Always include fallback logic. LLMs occasionally produce malformed output, especially under load. The fallback ensures your workflow never crashes — unclassifiable emails simply get flagged for human review instead of breaking the pipeline.

Step 3: Route by Category and Urgency

Add a Switch node that routes emails based on the classification. Configure these routing rules:

Switch on: {{ $json.category }}

Routes:
  "support"    --> Draft Support Reply
  "sales"      --> Draft Sales Reply
  "meeting"    --> Draft Scheduling Reply
  "feedback"   --> Log to Spreadsheet + Draft Thank-You
  "spam"       --> Archive/Delete (no reply)
  "newsletter" --> Archive (no reply)
  "internal"   --> Forward to Slack channel
  Default      --> Flag for manual review

For critical-urgency emails, add a second routing layer. Before the Switch node, add an IF node:

Condition: {{ $json.urgency }} equals "critical"

True  --> Send Slack/SMS alert immediately + Continue to normal routing
False --> Continue to normal routing

This way, a critical support email both triggers an immediate notification and gets a drafted reply.

Step 4: Generate Smart Replies

For each category that requires a response, add another HTTP Request node to Ollama. The key is tailoring the system prompt to each category so the AI generates appropriately toned replies.

Support Reply Prompt

{
  "model": "llama3:8b",
  "prompt": "You are a helpful customer support agent. Draft a professional reply to this support email.\n\nContext:\n- Category: {{ $json.category }}\n- Urgency: {{ $json.urgency }}\n- Sentiment: {{ $json.sentiment }}\n\nOriginal email from {{ $json.original_email.from }}:\nSubject: {{ $json.original_email.subject }}\nBody: {{ $json.original_email.body }}\n\nGuidelines:\n1. Acknowledge the issue specifically (don't be generic)\n2. If the customer sounds frustrated, show empathy first\n3. Provide concrete next steps or troubleshooting instructions\n4. For critical urgency: mention that the team has been alerted and is actively investigating\n5. Keep the reply under 150 words\n6. Sign off as 'Support Team'\n\nWrite ONLY the reply body. No subject line.",
  "stream": false,
  "options": {
    "temperature": 0.5,
    "num_predict": 500
  }
}

Sales Reply Prompt

{
  "model": "llama3:8b",
  "prompt": "You are a friendly sales representative. Draft a reply to this sales inquiry.\n\nOriginal email from {{ $json.original_email.from }}:\nSubject: {{ $json.original_email.subject }}\nBody: {{ $json.original_email.body }}\n\nGuidelines:\n1. Thank them for their interest\n2. Address their specific question or need\n3. Include a soft call to action (schedule a call, try a demo, etc.)\n4. Be warm but concise - under 120 words\n5. Sign off as 'Sales Team'\n\nWrite ONLY the reply body.",
  "stream": false,
  "options": {
    "temperature": 0.6,
    "num_predict": 400
  }
}

Scheduling Reply Prompt

{
  "model": "llama3:8b",
  "prompt": "Draft a brief scheduling reply to this email.\n\nFrom: {{ $json.original_email.from }}\nSubject: {{ $json.original_email.subject }}\nBody: {{ $json.original_email.body }}\n\nGuidelines:\n1. Confirm interest in meeting\n2. Suggest 2-3 time slots (use placeholder times like [Time Slot 1], [Time Slot 2])\n3. Ask about preferred meeting format (video call, phone, in-person)\n4. Keep it under 80 words\n\nWrite ONLY the reply body.",
  "stream": false,
  "options": {
    "temperature": 0.4,
    "num_predict": 300
  }
}

Notice the different temperatures: support replies (0.5) need some flexibility for empathetic language, sales replies (0.6) benefit from slightly more creative tone, and scheduling replies (0.4) should be more formulaic and predictable.

Step 5: Handle Spam and Low-Priority Mail

Not every email needs a reply. For emails classified as spam or newsletter, skip the reply-drafting step entirely. You can:

For the feedback category, log the feedback to a spreadsheet and send a brief thank-you reply. This creates a searchable feedback database without manual effort:

// Code node: structure feedback for logging
return [{
  json: {
    date: $json.original_email.date,
    from: $json.original_email.from,
    subject: $json.original_email.subject,
    sentiment: $json.sentiment,
    summary: $json.summary,
    full_text: $json.original_email.body
  }
}];

Prompt Engineering Tips for Email AI

After testing this workflow across hundreds of real-world emails, here are the patterns that produce the most reliable results:

1. Be explicit about output format

Always end classification prompts with "Return ONLY valid JSON, no other text." Without this, models frequently add explanatory text around the JSON, which breaks parsing.

2. Provide category definitions

Do not just list categories. Briefly describe what each one means. "support: Technical issues, bugs, account problems" gives the model much better classification accuracy than just "support."

3. Set word limits in reply prompts

Without explicit limits, the AI tends to write 300-500 word replies that feel robotic and over-detailed. "Keep the reply under 150 words" forces concise, natural-sounding responses.

4. Include the sentiment in reply context

Passing the detected sentiment to the reply-drafting prompt lets the AI adjust its tone. A reply to an "angry" customer leads with empathy; a reply to a "positive" email matches the upbeat tone.

5. Use temperature strategically

Going to Production: Checklist

Before letting this workflow handle your real inbox, run through these checks:

  1. Test with 50+ real emails — Manually verify the classification accuracy. You should see 85-95% accuracy with the prompts above. Adjust category definitions for your specific email patterns.
  2. Start with drafts, not sends — Configure the output to save replies as drafts in your email client rather than sending automatically. Review drafts for a week before enabling auto-send.
  3. Set HTTP timeouts to 120000ms — Local models can take up to 60 seconds per generation. The default n8n timeout is too short.
  4. Add error handling — Wrap the Ollama HTTP Request nodes in an Error Trigger workflow. If Ollama is down or returns garbage, the email should be flagged for manual handling, not lost.
  5. Monitor classification drift — Log classifications to a spreadsheet. If accuracy drops over time (perhaps your email patterns changed), update the category definitions in your prompt.
  6. Set up Ollama to start on boot — Use a systemd service or Docker restart policy to ensure Ollama survives server reboots.
# Systemd service for Ollama (save to /etc/systemd/system/ollama.service)
[Unit]
Description=Ollama LLM Service
After=network.target

[Service]
ExecStart=/usr/local/bin/ollama serve
Restart=always
RestartSec=5
Environment=OLLAMA_HOST=0.0.0.0

[Install]
WantedBy=multi-user.target
Performance tip: If you are processing high email volumes (100+ per day), consider using mistral:7b instead of llama3:8b for the classification step. Mistral is faster for short, structured output tasks and uses less RAM, freeing resources for the reply-drafting step where Llama 3 excels.

Email automation is just one piece of the puzzle. If you found this tutorial useful, these related workflows extend the concept:

Building each of these from scratch takes hours of prompt engineering, error handling, and testing. If you want production-ready versions that work out of the box, we have built all of them (and 7 more) as importable n8n templates.

Get All 11 Workflows — Ready to Import

The Self-Hosted AI Workflow Pack includes the email auto-responder from this tutorial plus 10 more production-ready n8n + Ollama workflows: content generation, lead scoring, document processing, competitor monitoring, and more.

$39 one-time — no subscriptions, no API costs, 30-day money-back guarantee

Get the Workflow Pack →

Free Samples

Want to try a workflow before buying? Grab these free, open-source templates:

Further Reading


Published by WorkflowForge · Self-Hosted AI Workflow Pack