So verhinderst du doppelte E-Mails im AI Agent Workflow, wenn ready_to_email wahr bleibt

Describe the problem/error/question

Hi everyone,
I’ve built a recruitment chatbot using the AI Agent node with Google Gemini, Telegram Trigger, Postgres Chat Memory, and Structured Output Parser. The bot interviews users in Algerian Darija and collects structured profile data (name, study field, skills, etc.).
The workflow:
Telegram Trigger → AI Agent → Postgres Memory → Structured Output Parser → IF node (checks ready_to_email === true) → Mailtrap (sends report to VP) → Send Message back to user
The problem:
Once the profile is complete, the AI sets ready_to_email: true and sends the email. But on the next user message, the AI still outputs ready_to_email: true (because the profile stays complete), so the IF node fires again and another duplicate email gets sent. This happens on every subsequent message.
What I’ve tried:
Added an email_sent boolean flag to the JSON schema and told the AI to set it to true after the first email, and never set ready_to_email: true again after that
Updated the IF node to check both ready_to_email === true AND email_sent === false
The AI sometimes forgets to set email_sent or still outputs ready_to_email: true on later turns
My question:
Is there a better way to make sure the email node only fires once per conversation? I thought about using a database to store a flag, or maybe there’s a built-in n8n node that acts as a one-time gate? I found the “Execute Once” option but I believe that only works within a single workflow execution, not across multiple messages.
Any advice on the cleanest way to handle this?
Thanks!

What is the error message (if any)?

Please share your workflow

Share the output returned by the last node

Information on your n8n setup

  • n8n version: 2.22.4
  • Database (default: SQLite): Postgresql (supabase)
  • n8n EXECUTIONS_PROCESS setting (default: own, main):
  • Running n8n via (Docker, npm, n8n cloud, desktop app):n8n cloud
  • Operating system: windows

@Hadiluno die sauberste Lösung ist, den LLM nicht zu trauen, dass er den E-Mail-Versand-Status speichert — externalisiere ihn. Da du bereits Supabase Postgres verbunden hast, füge eine 1-spalten Tabelle hinzu und sperre den Email-Node daran:

CREATE TABLE sent_emails (
  session_id TEXT PRIMARY KEY,
  sent_at TIMESTAMP DEFAULT NOW()
);

dann werfe diese 2 Nodes in deinen Workflow — einen vor dem IF, einen nach Mailtrap:

dann änder in deinem bestehenden IF-Node die Bedingung, um beides zu kombinieren:

  • {{ $('Structured Output Parser').item.json.ready_to_email }} === true
  • {{ $('Check Email Sent').all().length }} === 0

jetzt kann der LLM ready_to_email hundertmal umlegen — das Gate lebt in der DB, nicht im Modell. schnelle Frage: du nutzt die telegram chat.id als Session-Schlüssel für die Postgres Chat Memory, richtig? wenn ja, dieselbe id funktioniert als Email-Versand-Schlüssel, keine zusätzliche Verkabelung nötig.

Hi @Hadiluno

The problem is that you are asking the AI to act as a database. AI models are great at conversation, but they are “probabilistic,” meaning they can forget or ignore specific instructions over time. When you ask it to remember that an email was already sent, it eventually slips up and triggers the “ready” flag again because the user’s profile is still technically complete.

The solution is to move the “Email Sent” flag out of the AI’s head and into a real database table. Instead of trusting the AI to track the status, you create a simple list in Postgres that tracks each user’s ID and whether their email has been sent. This creates a “single source of truth” that never forgets.

In your workflow, you would add a step at the beginning to check this database for the user’s status. Then, your IF node will only send the email if two things are true: the AI says the profile is ready AND the database says the email hasn’t been sent yet. Once the email is sent, the workflow immediately updates the database to “true,” effectively locking the gate.

This approach is much cleaner because it simplifies the AI’s job. You can remove all the confusing “email_sent” instructions from your prompt, allowing the AI to focus entirely on the interview. This makes the bot more reliable, reduces errors, and ensures that your VP only receives one professional report per candidate.

To implement this, you first need to run this SQL command in your Postgres database to create the status tracking table:

CREATE TABLE user_status (
    chat_id TEXT PRIMARY KEY,
    email_sent BOOLEAN DEFAULT FALSE
);

Here is the workflow

Note: You will need to re-select your Postgres credentials after importing.

VIELEN DANK EUCH ALLEN FÜR DIE HILFE, ES FUNKTIONIERT JETZT!!!, dieses Problem hat mich tagelang genervt. :yellow_heart::yellow_heart:

@Hadiluno bitte markiere die relevante Antwort als Lösung, vielen Dank!!!

Gerne! Freut mich, dass ich und @kjooleng helfen konnten!