Why Automate Your Tasks?
Hi all 👋! As an app developer, I’m excited to share how you can create simple yet powerful agents to automate your daily tasks.
📬 Like many of you, I receive an overwhelming number of emails every day. Despite my best efforts, achieving the elusive Inbox Zero remains a challenge. Sorting through emails like order confirmations and shipping updates is tedious and time-consuming.
But here’s the good news: automation can save the day!
🤖 I’ve written a basic script leveraging AI to help automate email categorization—and you can, too.
In this article, I’ll share reusable code snippets to help you build your own automation agents tailored to your needs. 🚀
The Beauty of Automation
There are countless tools, including no-code platforms, that can handle entire processes for you. However, I prefer breaking tasks into modular code snippets. Why?
- Flexibility: Modular code can easily adapt to changing requirements.
- Reusability: Write once, use forever.
- Maintainability: Small, independent chunks of code are easier to debug and improve.
By taking an incremental approach, you can gradually replace manual steps with automated ones.
👩💻 My personal go-to tool for prototyping scripts is Znote—a notebook with live coding and AI that helps me track and enhance my workflows. Otherwise use your favorite IDE!
Let’s Build an Email Automation Agent
Goals
When a new email arrives, we want to:
- Read the email and extract relevant information.
- Use an LLM to determine its category from a predefined list.
- Create Gmail labels (if they don’t already exist).
- Update the email’s labels to reflect the assigned category.
Getting Started
Prerequisites
Step 1: Enable Gmail API
- Go to the Google Cloud Console and enable the Gmail API.
- Set up OAuth credentials for a desktop application. Follow these steps to download your
google-credentials.json
file and place it in your project directory.
Step 2: Install Ollama
Download Ollama to run a local LLM. Once installed, download a model:
ollama pull mistral
Step 3: Install Dependencies
Install the required Node.js libraries:
npm install -S @google-cloud/local-auth googleapis openai
Writing the Code
1. Authenticate with Google API
Set up an OAuth connection to Gmail:
// google-api.js
const fs = require("fs");
const path = require("path");
const { authenticate } = require("@google-cloud/local-auth");
const { google } = require("googleapis");
class GoogleAPI {
constructor(credentialFilename) {
this.TOKEN_PATH = path.join(__dirname, `token-${credentialFilename}`);
this.CREDENTIALS_PATH = path.join(__dirname, credentialFilename);
this.SCOPES = [
"https://mail.google.com/",
"https://www.googleapis.com/auth/gmail.modify",
];
}
async authorize() {
const loadSavedCredentials = () => {
try {
const content = fs.readFileSync(this.TOKEN_PATH);
return google.auth.fromJSON(JSON.parse(content));
} catch {
return null;
}
};
const saveCredentials = (client) => {
const keys = JSON.parse(fs.readFileSync(this.CREDENTIALS_PATH));
fs.writeFileSync(
this.TOKEN_PATH,
JSON.stringify({
type: "authorized_user",
client_id: keys.installed.client_id,
client_secret: keys.installed.client_secret,
refresh_token: client.credentials.refresh_token,
})
);
};
let client = await loadSavedCredentials();
if (!client) {
client = await authenticate({
scopes: this.SCOPES,
keyfilePath: this.CREDENTIALS_PATH,
});
if (client.credentials) saveCredentials(client);
}
return client;
}
}
module.exports = GoogleAPI;
2. Create Gmail Labels
Use this function to create labels and retrieve their IDs:
async function createAndGetLabels(labelsToCreate) {
const google = await getGoogleClient();
const gmail = google.gmail({ version: "v1" });
const existingLabels = (await gmail.users.labels.list({ userId: "me" })).data.labels || [];
const labelsMap = new Map();
for (const label of labelsToCreate) {
const existing = existingLabels.find((l) => l.name === label);
if (existing) {
labelsMap.set(label, existing.id);
} else {
const res = await gmail.users.labels.create({
userId: "me",
requestBody: { name: label },
});
labelsMap.set(label, res.data.id);
}
}
return labelsMap;
}
3. Read Emails
Extract details from message api:
async function readEmails(gmail, maxResults = 10) {
const res = await gmail.users.messages.list({ userId: "me", labelIds: ["INBOX"], maxResults });
return Promise.all(
res.data.messages.map(async ({ id }) => {
const email = await gmail.users.messages.get({ userId: "me", id });
return email.data;
})
);
}
4. Decrypt relevants infos
Extract meaningful details from emails:
function extractMailInfos(mail) {
// Define the headers to extract
const relevantHeaders = ["Date", "Subject"];
// Extract and structure the relevant headers
const headers = mail.payload.headers
.filter(header => relevantHeaders.includes(header.name))
.reduce((accumulator, header) => {
accumulator[header.name] = header.value;
return accumulator;
}, {});
// Add the unique mail ID directly to the headers object
headers.id = mail.id;
return headers;
}
5. Use an LLM for Categorization
Integrate Ollama or OpenAI to classify emails:
async function classifyEmail(prompt) {
const { OpenAI } = require("openai");
const openai = new OpenAI({ baseURL: "http://127.0.0.1:11434/v1", apiKey: "not-needed" });
const response = await openai.chat.completions.create({
model: "mistral",
temperature: 0.3,
messages: [{ role: "user", content: prompt }],
});
return response.choices[0].message.content.trim();
}
Putting It All Together
Here’s how everything works together:
const labelsToCreate = ["Order", "Shipping", "Newsletter", "Other"];
const labelsMap = await createAndGetLabels(labelsToCreate);
const promptSystem = `
Your role is to determine the category of the emails by choosing from the categories listed below.
Here are the possible categories:
- Order
- Shipping
- Newsletter
- Other
You must return in response the name of the category without further explanation and without quotation marks.
`
const rawEmails = await readEmails(gmail);
const emails = rawEmails.map(m => extractMailInfos(m));
for (const email of emails) {
const prompt = `${promptSystem}
Categorize this email: ${email.Subject}`;
const category = await classifyEmail(prompt);
if (labelsMap.has(category)) {
await gmail.users.messages.modify({
userId: "me",
id: email.id,
requestBody: {
addLabelIds: [labelsMap.get(category)],
//removeLabelIds: ["INBOX"],
},
});
}
}
🎉 That’s it! Your inbox is now smarter and more organized.
Go further
For more automation ideas and reusable scripts, check out this Gallery. You will find more advanced examples to export for reading email content, sending drafts, and building everything you need for fully automated responses.
👉 ❓I’d love to hear about the libraries you use to build your automations as a developer!
Top comments (0)