Email Automation with AI Chatbots
Set up AI-powered email automation with OpenClaw or OpenClaw. Automate outreach, responses, and email management through your VPS.
Overview
Combine your AI chatbot with email automation for powerful workflows. From drafting responses to managing outreach campaigns, your VPS-hosted bot can handle email tasks triggered by chat commands.
Use Cases
- Email Drafting: "Draft a follow-up email to John about the project"
- Response Automation: Auto-reply to common inquiries
- Outreach Management: Prepare personalized emails at scale
- Email Summaries: "Summarize my unread emails"
- Follow-up Reminders: Track and prompt follow-ups
Architecture
Chat Command (Discord/WhatsApp)
↓
[VPS - OpenClaw/OpenClaw]
↓
[AI generates email content]
↓
[Email sent via SMTP]
Basic Setup
1. Install Dependencies
npm install nodemailer
2. Environment Configuration
# SMTP Settings
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your@gmail.com
SMTP_PASSWORD=app-specific-password
SMTP_FROM=Your Name <your@gmail.com>
# Email Features
EMAIL_ENABLED=true
EMAIL_DRAFT_MODE=true # Review before sending
3. Basic Email Function
const nodemailer = require('nodemailer');
const transporter = nodemailer.createTransport({
host: process.env.SMTP_HOST,
port: process.env.SMTP_PORT,
secure: false,
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASSWORD
}
});
async function sendEmail({ to, subject, body }) {
const info = await transporter.sendMail({
from: process.env.SMTP_FROM,
to,
subject,
text: body,
html: body.replace(/\n/g, '<br>')
});
return info.messageId;
}
Chat-to-Email Workflow
Draft Mode (Recommended)
Review emails before sending:
async function handleEmailCommand(message) {
const prompt = message.content.replace('/email', '').trim();
// Generate email with AI
const draft = await generateEmailDraft(prompt);
// Store for review
const draftId = await saveDraft(draft);
return `📧 **Email Draft #${draftId}**
**To:** ${draft.to}
**Subject:** ${draft.subject}
${draft.body}
---
Reply \`/send ${draftId}\` to send, or \`/edit ${draftId}\` to modify.`;
}
AI Email Generation
async function generateEmailDraft(instruction) {
const response = await claude.messages.create({
model: 'claude-3-5-sonnet-20241022',
messages: [{
role: 'user',
content: `Generate a professional email based on this instruction:
${instruction}
Return in this JSON format:
{
"to": "recipient@example.com",
"subject": "Email subject",
"body": "Email body text"
}
If no recipient specified, use [RECIPIENT] as placeholder.`
}]
});
return JSON.parse(response.content[0].text);
}
Example Interaction
User: /email follow up with sarah@company.com about the proposal we discussed last week
Bot:
📧 Email Draft #42
To: sarah@company.com
Subject: Following Up on Our Proposal Discussion
Hi Sarah,
I hope this email finds you well. I wanted to follow up on the proposal
we discussed last week.
Have you had a chance to review the details? I'd be happy to answer any
questions or clarify any points that might be helpful for your decision.
Please let me know if you'd like to schedule a call to discuss further.
Best regards,
[Your Name]
---
Reply `/send 42` to send, or `/edit 42` to modify.
Advanced Features
Email Templates
Store common templates:
const TEMPLATES = {
follow_up: {
subject: 'Following Up',
body: `Hi {name},
I wanted to follow up on our previous conversation about {topic}.
{custom_content}
Best regards,
{sender_name}`
},
meeting_request: {
subject: 'Meeting Request: {topic}',
body: `Hi {name},
I'd like to schedule a meeting to discuss {topic}.
Would any of these times work for you?
{available_times}
Looking forward to hearing from you.
Best regards,
{sender_name}`
}
};
async function useTemplate(templateName, variables) {
const template = TEMPLATES[templateName];
let { subject, body } = template;
for (const [key, value] of Object.entries(variables)) {
subject = subject.replace(`{${key}}`, value);
body = body.replace(new RegExp(`{${key}}`, 'g'), value);
}
return { subject, body };
}
Contact Management
Simple contact storage:
const contacts = new Map();
async function addContact(email, name, notes) {
contacts.set(email, { name, notes, lastContact: null });
}
async function getContactContext(email) {
const contact = contacts.get(email);
if (contact) {
return `Recipient: ${contact.name}
Previous notes: ${contact.notes}
Last contact: ${contact.lastContact}`;
}
return '';
}
Outreach Campaigns
Prepare bulk personalized emails:
async function prepareOutreach(recipients, template, customData) {
const drafts = [];
for (const recipient of recipients) {
const personalized = await claude.messages.create({
model: 'claude-3-5-sonnet-20241022',
messages: [{
role: 'user',
content: `Personalize this email for ${recipient.name} at ${recipient.company}:
Template: ${template}
Their context: ${recipient.context}
Keep the core message but add relevant personalization.`
}]
});
drafts.push({
to: recipient.email,
subject: customData.subject,
body: personalized.content[0].text
});
}
return drafts;
}
Command: /outreach campaign_name
Bot:
📧 Prepared 15 emails for campaign "Q1 Outreach"
Preview first 3:
1. john@acme.com - Personalized for software industry
2. sarah@techco.com - Mentioned their recent funding
3. mike@startup.io - Referenced mutual connection
Reply `/review-outreach campaign_name` to review all
Reply `/send-outreach campaign_name` to send all
Email Reading (IMAP)
Setup IMAP
npm install imap mailparser
const Imap = require('imap');
const { simpleParser } = require('mailparser');
const imap = new Imap({
user: process.env.IMAP_USER,
password: process.env.IMAP_PASSWORD,
host: process.env.IMAP_HOST,
port: 993,
tls: true
});
async function getUnreadEmails() {
return new Promise((resolve, reject) => {
imap.once('ready', () => {
imap.openBox('INBOX', false, (err, box) => {
imap.search(['UNSEEN'], (err, results) => {
// Fetch and parse emails
const fetch = imap.fetch(results, { bodies: '' });
const emails = [];
fetch.on('message', (msg) => {
msg.on('body', async (stream) => {
const parsed = await simpleParser(stream);
emails.push({
from: parsed.from.text,
subject: parsed.subject,
date: parsed.date,
text: parsed.text
});
});
});
fetch.once('end', () => {
imap.end();
resolve(emails);
});
});
});
});
imap.connect();
});
}
Email Summary Command
async function handleSummaryCommand() {
const emails = await getUnreadEmails();
if (emails.length === 0) {
return "📭 No unread emails!";
}
const summary = await claude.messages.create({
model: 'claude-3-5-sonnet-20241022',
messages: [{
role: 'user',
content: `Summarize these ${emails.length} emails briefly:
${emails.map(e => `From: ${e.from}
Subject: ${e.subject}
Preview: ${e.text.substring(0, 200)}...
---`).join('\n')}`
}]
});
return `📧 **Email Summary (${emails.length} unread)**\n\n${summary.content[0].text}`;
}
Security Considerations
Never Store Plain Passwords
# Use app-specific passwords
SMTP_PASSWORD=xxxx-xxxx-xxxx-xxxx # Gmail app password
# Or OAuth2 (more secure)
GMAIL_CLIENT_ID=...
GMAIL_CLIENT_SECRET=...
GMAIL_REFRESH_TOKEN=...
Limit Send Permissions
const ALLOWED_SENDERS = ['your_discord_id'];
async function handleEmailCommand(message) {
if (!ALLOWED_SENDERS.includes(message.author.id)) {
return "You don't have permission to send emails.";
}
// Continue...
}
Rate Limiting
const sendLimits = new Map();
function checkSendLimit(userId) {
const today = new Date().toDateString();
const key = `${userId}-${today}`;
const sent = sendLimits.get(key) || 0;
if (sent >= 50) {
return false;
}
sendLimits.set(key, sent + 1);
return true;
}
Confirmation for External Recipients
const INTERNAL_DOMAINS = ['yourcompany.com', 'yourdomain.co.uk'];
async function validateRecipient(email) {
const domain = email.split('@')[1];
if (!INTERNAL_DOMAINS.includes(domain)) {
return {
needsConfirmation: true,
message: `⚠️ External recipient detected (${domain}). Confirm with /confirm-send`
};
}
return { needsConfirmation: false };
}
Best Practices
Do's
- ✅ Always use draft mode for new setups
- ✅ Log all sent emails
- ✅ Implement rate limiting
- ✅ Review AI-generated content before sending
- ✅ Use app-specific passwords
Don'ts
- ❌ Auto-send without review
- ❌ Store credentials in code
- ❌ Allow unlimited sends
- ❌ Skip recipient validation
- ❌ Use for spam or cold outreach abuse
Compliance Notes
GDPR/UK DPA
- Only email contacts who've consented
- Include unsubscribe option for marketing
- Keep records of consent
- Don't scrape emails
CAN-SPAM/PECR
- Include physical address in marketing emails
- Honor unsubscribe requests promptly
- Clear sender identification
Related Guides
Need Help?
Email automation requires careful setup. Our premium service includes email integration with proper security configuration.
Need a VPS for Your Bot?
We recommend Hostinger KVM 2 VPS - reliable, fast, and perfect for AI chatbots. Get started with our recommended setup.
Get Hostinger VPSNeed Help With Setup?
Got your VPS? Let us handle the technical work. Professional setup and maintenance for OpenClaw (formerly Clawd.bot).