Learn
Build an automated social media management agent with Dynamiq
Build an agent that reads a client list, drafts a personalized email for each contact and sends it through Mailgun after a person approves the drafts.

In short
This tutorial builds an agent that reads a client list, drafts a personalized email for each contact and sends the approved drafts through Mailgun. It uses the open-source Dynamiq SDK: an agent with a code interpreter to read the file, a small send tool and a human approval step. The same pattern works for any outreach where a person must sign off before anything goes out.
An automated social media management agent takes the repetitive part of client communication off a manager's plate: it reads a client list, writes a personalized message for each contact and sends it through your email provider. The version in this tutorial, built with the open-source Dynamiq SDK, drafts every email, asks a person to approve the batch and only then sends. That approval step is what makes the pattern safe to use with real clients.
What does the agent do?
The agent works through five steps in one run:
- Reads the client list in a sandboxed code interpreter, so it can handle CSV or spreadsheet files.
- Drafts one email per contact using each person's name, title, audience and interests.
- Shows the drafts and asks for approval before anything leaves the building.
- Sends the approved emails through Mailgun, one message per contact.
- Reports what it sent, so the run leaves a clear record.
Social media and marketing managers use this pattern for campaign follow-ups, event invitations and account updates, where every message should feel personal but the structure repeats.
What do you need?
- Python 3.10 or later and the SDK:
pip install dynamiq requests - An
OPENAI_API_KEYfor the model and anE2B_API_KEYfor the code sandbox - A Mailgun account with a verified sending domain, stored as
MAILGUN_API_KEY,MAILGUN_DOMAINandMAILGUN_FROM
Step 1: Prepare the client list
Any tabular file works. This example uses a CSV with fictional contacts:
email,audience,first_name,last_name,title,interests
jordan@example.com,Operations leaders exploring AI for support,Jordan,Lee,Head of Operations,customer experience
sam@example.com,Finance teams automating month-end close,Sam,Patel,Finance Director,reporting
Test with addresses you own, or with your provider's sandbox domain, before you point the agent at a real list.
Step 2: Create the send tool
The function_tool decorator turns a Python function into a tool the agent can call. Its type hints become the input schema, and its docstring tells the agent when to use it.
import os
import requests
from dynamiq.nodes.tools.function_tool import function_tool
@function_tool
def send_email(to: str, subject: str, text: str, **kwargs) -> str:
"""Send one approved plain-text email through Mailgun. Use only after the drafts are approved."""
response = requests.post(
f"https://api.mailgun.net/v3/{os.environ['MAILGUN_DOMAIN']}/messages", # EU domains use api.eu.mailgun.net
auth=("api", os.environ["MAILGUN_API_KEY"]),
data={"from": os.environ["MAILGUN_FROM"], "to": to, "subject": subject, "text": text},
timeout=30,
)
response.raise_for_status()
return f"Sent to {to}"
Keeping the tool this narrow is deliberate: it can send one plain-text email and nothing else. Any provider with an HTTP API works the same way.
Step 3: Create the agent
The agent gets three tools: a code interpreter to read the file, a feedback tool to ask for approval, and the send tool.
from dynamiq.connections import E2B as E2BConnection
from dynamiq.connections import OpenAI as OpenAIConnection
from dynamiq.nodes.agents import Agent
from dynamiq.nodes.llms import OpenAI
from dynamiq.nodes.tools.e2b_sandbox import E2BInterpreterTool
from dynamiq.nodes.tools.human_feedback import HumanFeedbackTool
agent = Agent(
name="Client outreach agent",
role=(
"You write short, personal emails to a company's clients. Read the client file with the "
"code interpreter. For each contact, draft one email that uses their name, title, audience "
"and interests, and ends with the signature you are given. Show all drafts and ask for "
"approval with the feedback tool. Send only the approved drafts, one email per contact, "
"then list what was sent."
),
llm=OpenAI(connection=OpenAIConnection(), model="gpt-4o", temperature=0.3),
tools=[
E2BInterpreterTool(connection=E2BConnection()), # reads E2B_API_KEY
HumanFeedbackTool(), # asks for approval in the console
send_email(),
],
max_loops=20,
)
Step 4: Run it with the client file
Pass the file in the files input. The agent uploads it to its sandbox and reads it with code.
import io
with open("clients.csv", "rb") as f:
client_file = io.BytesIO(f.read())
client_file.name = "clients.csv" # the agent sees the file under this name
result = agent.run(
input_data={
"input": (
"Draft a personalized email for every contact in the attached file. "
"Sign each one 'Best regards, the Dynamiq team'. Ask for approval before sending anything."
),
"files": [client_file],
}
)
print(result.output["content"])
The console shows the drafts and waits for your answer. Reply with approval, or with edits such as "shorten the second email", and the agent revises before it sends.
A version of this example, with a Mailgun tool written as a full custom node, lives in the SDK repository under examples/use_cases/smm_manager.
How do you keep automated outreach safe?
Sending email on a company's behalf is an action with consequences, especially in regulated industries. Build these controls in from the start:
- Approve before sending. On the Dynamiq platform, an approval can pause any tool step for a person, who can edit fields such as the subject or body before it runs.
- Respect consent and opt-outs. Email only contacts you have a lawful basis to contact, and include a way to unsubscribe.
- Check regulated wording. In financial services, marketing messages can need compliance review, so route those drafts to the right reviewer.
- Keep a record. Every run is traced, including which drafts were approved and what was sent.
Can you do this without writing code?
Yes. AI Coworker can run the same job from a chat message: connect your email and CRM, attach the client list and ask for drafts. It works in the browser and in Slack, Microsoft Teams and Telegram, and it can repeat the task on a schedule.
Mailgun, Gmail and HubSpot are among the 2,100+ app integrations an agent can use, so it can send through the provider you already have. Browse them on the integrations page.
FAQ
Can an AI agent send emails on its own?
Yes, if you give it a send tool. For anything that reaches clients, keep a person in the loop: have the agent draft first and send only what a reviewer approves, as in this tutorial.
Which email providers can the agent use?
Any provider with an API. This tutorial uses Mailgun through a small Python function; on the Dynamiq platform, the same agent can use Gmail, HubSpot, Mailgun and many other integrations without custom code.
How does the agent read a CSV or Excel file?
It uses a code interpreter running in a sandbox. The agent writes and runs Python to parse the file, which handles CSV, Excel and other formats without a special parser for each.
How do you stop the agent from emailing the wrong people?
Test against addresses you own or a sandbox domain, keep the send tool narrow, require approval before sending, and review the trace of each run. You can also check recipients against an allowlist inside the send function.
Can you schedule the agent to run every week?
Yes. AI Coworker supports scheduled tasks, and a deployed workflow can run on a cron schedule or when an event arrives from a connected app.



