A lead fills out your contact form.
AI drafts a useful reply. You approve it. Then the customer receives the same email twice.
The draft was fine. The approval was real. The workflow still created a problem.
When I think about useful AI automation, I care about what happens after the happy-path demo. For an email workflow, that means answering a practical question: can the system handle a retry without repeating a customer-facing action?
Here is a design approach for small teams building AI email automation in n8n. This is an architecture guide, not a claim that a particular workflow has been deployed or tested.
1. Give the AI a clear job
Use a simple brief: role, target, task, and output.
Role: draft assistant for inbound customer inquiries.
Target: people who have contacted the business.
Task: prepare a helpful reply using the inquiry and verified business information.
Output: a subject, draft body, missing information, and a reason for human review.
Keep prices, commitments, availability, and delivery dates grounded in actual records. If the information is missing, the draft should ask a question instead of inventing an answer.
The permission to write a draft should be separate from the permission to send it.
2. Approve the exact message
n8n supports human review before selected AI tools execute. A reviewer can approve or deny the proposed tool call, with the workflow waiting for that decision. The official documentation also explains how to include tool parameters in the review message. [1]
For an email, show the actual sender, recipient, CC/BCC, subject, body, and attachments. Add the inquiry that explains why the message is being sent.
My design recommendation is to bind approval to an immutable version of those details. If the recipient, content, or attachment changes, create a new version and request approval again. Also verify that the person approving is authorized to do so.
A green approval button should mean “send this message,” not “send whatever the next step produces.”
3. Identify the action before sending
Give each intended reply a stable action key, such as the account ID, inquiry ID, and response step. Keep the approved content version alongside it.
Do not generate a fresh action key on every retry. Otherwise, the same email looks like a new action each time. Do not use the recipient alone either; the same person can legitimately receive different messages.
For concurrent executions, use a database-enforced unique action key and an atomic transition from approved to sending. Only the execution that successfully claims the action continues.
PostgreSQL unique constraints can enforce uniqueness across one column or a group of columns. [2] The workflow still needs correctly implemented claim logic; a unique record by itself does not stop two workers from sending.
n8n's Remove Duplicates node can help filter repeated input. [3] Treat that as one layer, not proof that an external email can never be sent twice.
4. Treat an uncertain send as uncertain
Consider this sequence: the email provider accepts the message, but the connection drops before your workflow receives the response.
The workflow sees an error. The customer could already have the email.
For this proposed design, track separate states: pending review, approved, sending, submitted, rejected, expired, and unknown.
Use submitted to mean the provider accepted the request. That is different from delivery to the inbox, and different again from the recipient reading it.
If a send outcome is unclear, mark it unknown and pause automatic resending. Reconcile it against available provider records and message identifiers. A missing search result alone is not proof that the first send failed. Escalate unresolved cases to a person.
When a provider offers a documented idempotency feature, use it within its stated limits. A database and an external email API do not automatically share one transaction, so avoid promising exactly-once delivery.
5. Check whether approval is still relevant
Before claiming an approved message for sending, recheck the current customer and inquiry state.
Has the customer already replied? Has someone handled the request manually? Has the draft expired? Has the recipient opted out? Is the approved version still the current version?
Choose an approval deadline that fits the task. An appointment reply can become stale much faster than a general information request.
If a check fails, stop or return the item for review. Silence from a reviewer is not approval.
6. Make failures visible
n8n supports error workflows that begin with an Error Trigger and can notify a team when an execution fails. Its execution history helps investigate what happened. [4]
Keep enough operational context to trace the inquiry, action key, approved version, reviewer, timestamps, provider response, and final state. Limit access and retention, and avoid copying unnecessary customer content into alerts.
An error notification should point to the item needing attention. It should not blindly restart the send step.
Before launch, test these cases
• The same inquiry arrives twice: one intended reply is queued.
• Two executions claim the same action: only one proceeds to send.
• The approved draft changes: the old approval cannot release it.
• The reviewer rejects or ignores the request: no email is sent.
• The customer replies before dispatch: the queued follow-up is stopped.
• The provider response is lost: the action becomes unknown instead of immediately resending.
• The workflow restarts: unresolved sending actions enter reconciliation.
These are acceptance criteria for the implementation, not results from a test I have already run.
The question I would ask before connecting real customers
“What happens if this step runs twice?”
A good AI email workflow needs a clear answer. Start with one inbound use case, a reviewable draft, a controlled send step, and a visible recovery path. Add more autonomy only after the actual behavior has been tested.
Which part of your workflow is hardest to trust today: the draft, the approval, or the retry?
Sources
[1] n8n: Human-in-the-loop for tools: https://docs.n8n.io/advanced-ai/human-in-the-loop-tools/
[2] PostgreSQL: Constraints: https://www.postgresql.org/docs/current/ddl-constraints.html
[3] n8n: Remove Duplicates: https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.removeduplicates/
[4] n8n: Error handling: https://docs.n8n.io/flow-logic/error-handling/
#n8n #AIAutomation #WorkflowAutomation #AIAgents
How does this apply to your business?
Share the workflow or idea you’re considering.
Discuss This Topic