In recent years, artificial intelligence has moved from being reactive and conversational to more autonomous and task-oriented. This evolution brings us to the concept of Agentic AI — systems that can take actions based on context, data, and intent without being explicitly told every step.
In this application, we will walk through building a simple yet functional Agentic AI assistant that:
- Connects to your Gmail inbox
- Reads emails and understands natural language
- Extracts meeting intent and schedules calendar events
We will build this using Node.js, integrate OpenAI’s GPT-3.5, and deploy it to AWS EC2 for real-world use. This article assumes that you have some familiarity with Node.js and API integrations.
What is Agentic AI?
Agentic AI systems are proactive. They don’t just wait for user commands but operate semi-autonomously to perform tasks like a human assistant would. Think of them as goal-driven agents that interpret context and execute multi-step workflows.
In our use case:
- The AI will identify a meeting request from unstructured email
- Parse the required details (like time, attendees)
- Schedule it in your Google Calendar
This is a small but powerful example of Agentic AI in practice.
Tools and Technologies
- Node.js — JavaScript runtime for building our agent logic
- OpenAI GPT-3.5 — for understanding email context and extracting structured data
- Gmail API — to fetch user emails securely
- Google Calendar API — to create calendar events
- dotenv — for managing API keys and environment variables
- AWS EC2 — to host and run the solution continuously
Project Structure Explained
gmail-agentic-scheduler/
├── index.js # Main runner
├── openai.js # GPT extraction logic
├── gmail.js # Gmail fetch logic
├── calendar.js # Google Calendar event creation
├── analyze.js # Meeting data extraction
├── credentials.json # Google OAuth2 credentials
├── .env # Secrets file
Each file has a clear responsibility. This modularity makes the project easy to extend.
Setting Up API Access
1. Google Cloud Project
- Go to Google Cloud Console
- Create a new project
- Enable Gmail API and Google Calendar API
- Under “Credentials”:
- Create OAuth2 client ID (Web application)
- Set
http://localhost
as the redirect URI - Download the
credentials.json
file - Add your Gmail account as a test user in OAuth Consent screen
2. OpenAI API Key
- Go to OpenAI Platform
- Navigate to API Keys > Create Key
- Copy and store it securely
- Add this to your
.env
file:
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxx
3. Install Dependencies
npm install openai googleapis dotenv
How the Agent Works
Step 1: Read Emails
The agent connects to Gmail using OAuth2 and fetches the last 10–20 emails.
Step 2: Analyze with OpenAI
For each email, the text is sent to GPT-3.5 with a prompt like:
Extract meeting details from this email. Return JSON like:
{
"title": "Project Sync",
"start": "2025-07-01T15:00:00+05:30",
"end": "2025-07-01T16:00:00+05:30",
"attendees": ["alice@example.com"]
}
Step 3: Parse the Response
OpenAI returns a JSON structure. If all required fields are present, the agent proceeds to step 4.
Step 4: Create a Calendar Event
Using Google Calendar API, a new event is created and invite emails are sent automatically.
Sample Input Email
Hi Joshua,
Can we meet tomorrow at 11 AM IST to discuss the Q3 roadmap? Please invite alice@example.com and bob@example.com as well.
Thanks,
John
GPT-3.5 Output
{
"title": "Q3 Roadmap Discussion",
"start": "2025-07-01T11:00:00+05:30",
"end": "2025-07-01T12:00:00+05:30",
"attendees": ["alice@example.com", "bob@example.com"]
}
Code Files
index.js (Main runner)
import fs from 'fs';
import readline from 'readline';
import { google } from 'googleapis';
import { readEmails } from './gmail.js';
import { createEvent } from './calendar.js';
import { analyzeEmail } from './analyze.js';
const SCOPES = [
'https://www.googleapis.com/auth/gmail.readonly',
'https://www.googleapis.com/auth/calendar.events'
];
const TOKEN_PATH = 'token.json';
function authorize(credentials, callback) {
const { client_secret, client_id, redirect_uris } = credentials.installed;
const oAuth2Client = new google.auth.OAuth2(client_id, client_secret, redirect_uris[0]);
if (fs.existsSync(TOKEN_PATH)) {
oAuth2Client.setCredentials(JSON.parse(fs.readFileSync(TOKEN_PATH)));
callback(oAuth2Client);
} else {
const authUrl = oAuth2Client.generateAuthUrl({ access_type: 'offline', scope: SCOPES });
console.log('Authorize this app by visiting:', authUrl);
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
rl.question('Enter code from page: ', (code) => {
rl.close();
oAuth2Client.getToken(code).then(({ tokens }) => {
oAuth2Client.setCredentials(tokens);
fs.writeFileSync(TOKEN_PATH, JSON.stringify(tokens));
callback(oAuth2Client);
});
});
}
}
async function runAgent(auth) {
const emails = await readEmails(auth);
for (const email of emails) {
console.log(`\n From: ${email.from}\n${email.body}`);
try {
const parsedRaw = await analyzeEmail(email.body);
console.log('Raw OpenAI output:', parsedRaw);
const parsed = JSON.parse(parsedRaw);
if (parsed.title && parsed.start && parsed.end && parsed.attendees?.length) {
await createEvent(auth, parsed);
} else {
console.log('No valid meeting intent found.');
}
} catch (err) {
console.log('Could not parse meeting data.');
console.error(err.message);
}
}
}
fs.readFile('credentials.json', (err, content) => {
if (err) return console.error('credentials.json not found');
authorize(JSON.parse(content), runAgent);
});
openai.js
import OpenAI from 'openai';
import dotenv from 'dotenv';
dotenv.config();
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
export default openai;
gmail.js
import { google } from 'googleapis';
export async function readEmails(auth) {
const gmail = google.gmail({ version: 'v1', auth });
const res = await gmail.users.messages.list({ userId: 'me', maxResults: 5 });
const messages = res.data.messages || [];
const emails = [];
for (let msg of messages) {
const full = await gmail.users.messages.get({ userId: 'me', id: msg.id, format: 'full' });
const payload = full.data.payload;
const headers = payload.headers || [];
const from = headers.find(h => h.name === 'From')?.value || 'Unknown';
let body = '';
if (payload.parts) {
const part = payload.parts.find(p => p.mimeType === 'text/plain');
if (part?.body?.data) {
body = Buffer.from(part.body.data, 'base64').toString();
}
} else if (payload.body?.data) {
body = Buffer.from(payload.body.data, 'base64').toString();
}
emails.push({ from, body });
}
return emails;
}
analyze.js
import openai from './openai.js';
export async function analyzeEmail(text) {
const prompt = `
Extract meeting details from this email. Return JSON like:
{
"title": "Project Sync",
"start": "2025-07-01T15:00:00+05:30",
"end": "2025-07-01T16:00:00+05:30",
"attendees": ["person@example.com"]
}
Email: "${text}"
`;
const res = await openai.chat.completions.create({
model: 'gpt-4.1',
messages: [{ role: 'user', content: prompt }]
});
return res.choices[0].message.content;
}
calendar.js
import { google } from 'googleapis';
export async function createEvent(auth, details) {
const calendar = google.calendar({ version: 'v3', auth });
const event = {
summary: details.title,
start: { dateTime: details.start, timeZone: 'Asia/Kolkata' },
end: { dateTime: details.end, timeZone: 'Asia/Kolkata' },
attendees: details.attendees.map(email => ({ email }))
};
const res = await calendar.events.insert({ calendarId: 'primary', resource: event });
console.log('Event created:', res.data.htmlLink);
}
Deploying on AWS EC2
Step 1: Launch EC2 Instance
- Choose Ubuntu 22.04 LTS
- t2.micro (Free tier eligible)
- Allow SSH port 22
Step 2: SSH and Set Up Environment
ssh -i agent-key.pem ubuntu@<your-ec2-public-ip>
sudo apt update && sudo apt install nodejs npm unzip git -y
Step 3: Upload and Configure Project
- Clone via Git or SCP your zipped project
- Install dependencies
- Add
.env
andcredentials.json
Step 4: Run the Agent
node index.js # For manual testing
Step 5: Automate with PM2 or Cron
PM2:
npm install -g pm2
pm2 start index.js --name gmail-agent
pm2 save
Cron:
crontab -e
*/30 * * * * /usr/bin/node /home/ubuntu/gmail-agentic-scheduler/index.js >> /home/ubuntu/gmail-agentic-scheduler/logs/run.log 2>&1
Test email
Subject: Sync Meeting
Body:
Hi John,
Let's meet on Friday at 3 PM IST to review the Q2 performance.
Please include James (james@company.com) and Tim (tim@company.com).
Thanks,
Ankit
Extending the Agent
You can take this project much further:
- Add natural language support for rescheduling or canceling meetings
- Integrate Zoom or Google Meet link generation
- Use LangChain or AutoGen to chain multiple tools
- Add a web dashboard or mobile alerts
Key Takeaways
- Agentic AI can automate tedious workflows like meeting scheduling.
- Combining OpenAI + Gmail + Calendar makes a powerful productivity tool.
- Deploying on AWS EC2 makes it scalable, secure, and always-on.
This is just the beginning — you can extend this into a full personal assistant.
About the Author
Joshua Salema works as a Practice Lead – Low Code Digital at Zimetrics. He is an OutSystems certified Professional and is a passionate advocate for the implementation of architectural best practices. Joshua collaborates closely with cross-functional teams to ensure the development and delivery of secure and highly scalable applications utilizing the OutSystems platform. In addition to his core responsibilities, Joshua finds fulfillment in mentoring fellow developers and actively engages in multiple forums as a speaker within the OutSystems Community.