<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Adam</title>
    <description>The latest articles on DEV Community by Adam (@adamhassan).</description>
    <link>https://dev.to/adamhassan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4219097%2F0be88516-76c9-47ae-b036-15c15d9d5de0.jpg</url>
      <title>DEV Community: Adam</title>
      <link>https://dev.to/adamhassan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/adamhassan"/>
    <language>en</language>
    <item>
      <title>Building an AI Email Assistant with n8n &amp; Ollama: Part 1</title>
      <dc:creator>Adam</dc:creator>
      <pubDate>Sat, 31 Oct 2026 14:31:56 +0000</pubDate>
      <link>https://dev.to/adamhassan/building-an-ai-email-assistant-with-n8n-ollama-part-1-3f7j</link>
      <guid>https://dev.to/adamhassan/building-an-ai-email-assistant-with-n8n-ollama-part-1-3f7j</guid>
      <description>&lt;p&gt;&lt;em&gt;Exploring how a locally hosted AI model can identify actionable emails, distinguish between responsibilities and produce structured data for automation.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Managing a busy inbox isn't just about the volume of emails. It's about identifying which messages actually require your attention.&lt;/p&gt;

&lt;p&gt;In an operational environment, emails contain requests, updates, questions, confirmations and ongoing conversations. Some require immediate action, some need following up, and others are simply informational.&lt;/p&gt;

&lt;p&gt;What interests me is whether AI can help distinguish between them.&lt;/p&gt;

&lt;p&gt;I'm building a prototype that analyses emails, identifies potential tasks and determines whether those tasks are actually the recipient's responsibility.&lt;/p&gt;

&lt;p&gt;The longer-term ambition is to turn those decisions into an organised task register, with the ability to correct the AI's mistakes and improve its assessments over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The technology
&lt;/h2&gt;

&lt;p&gt;I've chosen three technologies for the initial prototype:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;n8n:&lt;/strong&gt; A workflow automation platform that connects applications and controls how data moves between them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ollama:&lt;/strong&gt; Software that allows language models to run locally, without relying on an external AI service for inference.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Qwen3 8B:&lt;/strong&gt; The language model responsible for analysing the email content.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm running the prototype on an Apple Silicon Mac with 24 GB of memory.&lt;/p&gt;

&lt;p&gt;Running the model locally was an intentional choice. I wanted to explore how much AI-powered processing could be performed without sending email content to an external model provider.&lt;/p&gt;

&lt;p&gt;For now, the system uses entirely fictional emails. It isn't connected to a live mailbox.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the first workflow
&lt;/h2&gt;

&lt;p&gt;The initial n8n workflow is straightforward:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manual Trigger → Edit Fields → Basic LLM Chain&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsi6b9vuivokoqzsobjkq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsi6b9vuivokoqzsobjkq.png" alt="n8n workflow showing Manual Trigger, Edit Fields and Basic LLM Chain, connected to Ollama Chat Model and Structured Output Parser." width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 1: The initial n8n workflow, connecting a sample email input to the locally running Qwen3 8B model through Ollama, with structured output parsing.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The Manual Trigger starts the automation.&lt;/p&gt;

&lt;p&gt;Edit Fields supplies a fictional email containing a sender, subject and message body.&lt;/p&gt;

&lt;p&gt;Basic LLM Chain passes that information to Qwen3 through the Ollama Chat Model.&lt;/p&gt;

&lt;p&gt;I also added a Structured Output Parser so the AI returns consistent, machine-readable information rather than an ordinary paragraph.&lt;/p&gt;

&lt;p&gt;Each assessment contains four properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;action_required&lt;/code&gt;: YES, NO or UNCERTAIN&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;task&lt;/code&gt;: A description of the action required&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;reason&lt;/code&gt;: The explanation behind the decision&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;priority&lt;/code&gt;: HIGH, MEDIUM or LOW&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is important because I eventually want the results to populate a database automatically.&lt;/p&gt;

&lt;p&gt;For example, the extracted task could become a record title, while its priority determines how prominently it appears in a dashboard.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting the data flowing
&lt;/h3&gt;

&lt;p&gt;One of the first challenges was ensuring that the AI actually received the information from the preceding node.&lt;/p&gt;

&lt;p&gt;Initially, Qwen3 returned a perfectly formatted response explaining that it couldn't determine whether action was required because no email information had been supplied.&lt;/p&gt;

&lt;p&gt;The problem wasn't the model itself. It was how I'd configured the prompt in n8n.&lt;/p&gt;

&lt;p&gt;The solution was to use dynamic expressions to reference the preceding node's data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;{{ $json.sender }}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{{ $json.subject }}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{{ $json.body }}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once these expressions were configured correctly, the AI could analyse the supplied email rather than a hardcoded example.&lt;/p&gt;

&lt;p&gt;It was a useful introduction to the distinction between an AI model working correctly and an automation successfully supplying it with the right information.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first successful test
&lt;/h2&gt;

&lt;p&gt;I initially tested the workflow using a fictional email from a distributor confirming that a revised programme master had been delivered.&lt;/p&gt;

&lt;p&gt;The sender asked the recipient to confirm receipt and report any issues.&lt;/p&gt;

&lt;p&gt;The model returned:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Action required:&lt;/strong&gt; YES&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task:&lt;/strong&gt; Confirm receipt of the revised master and check for issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Priority:&lt;/strong&gt; MEDIUM&lt;/p&gt;

&lt;p&gt;The response was sensible, and the structured output worked as intended.&lt;/p&gt;

&lt;p&gt;At this point, I had a functioning workflow that could accept email information and return a structured assessment.&lt;/p&gt;

&lt;p&gt;However, the next test revealed a more interesting problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Identifying tasks isn't the same as identifying responsibility
&lt;/h2&gt;

&lt;p&gt;I created another fictional email, this time addressed to a Scheduling department.&lt;/p&gt;

&lt;p&gt;The message requested that Scheduling update a programme's transmission date. It also explicitly stated that Programme Delivery was copied for visibility only and wasn't required to take action.&lt;/p&gt;

&lt;p&gt;I expected the AI to return &lt;strong&gt;NO ACTION REQUIRED&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead, it returned:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Action required:&lt;/strong&gt; YES&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task:&lt;/strong&gt; Update the transmission date for Episode 3 to Wednesday.&lt;/p&gt;

&lt;p&gt;Interestingly, the model hadn't misunderstood the email's content. It correctly identified the requested task.&lt;/p&gt;

&lt;p&gt;What it failed to recognise was that the task belonged to somebody else.&lt;/p&gt;

&lt;p&gt;The AI was effectively answering:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Does this email contain an action?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But the question I needed answered was:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Does this email contain an action that I'm personally responsible for?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That distinction is fundamental to the usefulness of the system.&lt;/p&gt;

&lt;p&gt;In a busy operational environment, an email might contain several requests, but only some will be relevant to a particular recipient.&lt;/p&gt;

&lt;p&gt;I've since revised the prompt to distinguish more explicitly between personal responsibilities, actions assigned to others and situations where responsibility is uncertain.&lt;/p&gt;

&lt;p&gt;The next step is to test whether those revised instructions produce more reliable classifications.&lt;/p&gt;

&lt;h2&gt;
  
  
  What comes next?
&lt;/h2&gt;

&lt;p&gt;The prototype has demonstrated that n8n can communicate with a locally running language model and return structured assessments of sample emails.&lt;/p&gt;

&lt;p&gt;But it's still an early experiment.&lt;/p&gt;

&lt;p&gt;My next objectives are to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Improve the accuracy of responsibility classification.&lt;/li&gt;
&lt;li&gt;Build a persistent feedback mechanism that remembers corrections.&lt;/li&gt;
&lt;li&gt;Develop a database and dashboard for managing identified tasks.&lt;/li&gt;
&lt;li&gt;Explore how the system could reliably track unresolved actions across email conversations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The plan is to use Airtable as a task management interface, with each identified action recorded alongside the sender's name, organisation, email address, date received, a summary of the request, priority and task status. This would provide a centralised, actionable overview of outstanding responsibilities rather than simply a list of flagged emails.&lt;/p&gt;

&lt;p&gt;Any eventual integration with a real organisational mailbox would also require appropriate access permissions and security controls.&lt;/p&gt;

&lt;p&gt;For now, I'm concentrating on the classification problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The goal isn't simply to build an AI that identifies tasks in emails. It's to build a personal assistant that automatically turns my busy inbox into an organised, prioritised list of things I need to do.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>n8n</category>
      <category>ollama</category>
      <category>ai</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
