Listen to this story
This story contains new, firsthand information uncovered by the writer.
This story contains AI-generated text. The author has used AI either for research, to generate outlines, or write the text itself.
With work and private life blending more than ever, managing an overflowing inbox can be overwhelming. But what if a tool could draft replies for you, only needing your review? Meet AutoResponder AI: a serverless email assistant on AWS that uses AI to streamline communication. This article will break down how it works and how it can make handling emails easier.
AutoResponder AI is an intelligent Gmail add-on that can help you manage emails and prevent inbox overload. It scans unread emails, detects sentiment, and drafts replies for those that need a response, saving them for your review. Once drafts are ready, it notifies you via email or SMS, keeping you updated. Built on a secure, cost-effective serverless system, it's ideal for busy professionals, customer service teams, or anyone who wants to stay responsive with less hassle.
AutoResponder AI is useful for business professionals, executives, sales teams, and customer service departments because it brings the might of AI-driven automation to your inbox management effort.
To access Gmail via API, you need OAuth credentials from Google Cloud Console.
Create a Google Cloud Project
Open the Google Cloud Console website -> Select New Project -> You may name it GmailAutoReply or whatever you choose -> Click on Create.
Enable Gmail API
Go to APIs & Services.
Enable APIs and Services, search for Gmail API and enable it.
Create OAuth Credentials
Navigate to APIs & Services -> Credentials -> Create Credentials -> OAuth client ID.
Choose the Application type: Desktop app and name it Lambda Gmail Client.
Click on Create and download client_secret_xxx.json
file.
Generate Access and Refresh Tokens:
Make sure you have the right Python libraries installed on your local machine::
pip install google-auth-oauthlib google-api-python-client
Use the following Python script to generate tokens (replace 'path/to/your/client_secret.json' with the path to your downloaded JSON file):
Run this Python script to generate access and refresh tokens:
from google_auth_oauthlib.flow import InstalledAppFlow
scopes = ['https://mail.google.com/']
flow = InstalledAppFlow.from_client_secrets_file(
'path/to/your/client_secret.json', scopes)
credentials = flow.run_local_server(port=0)
print(f"Access Token: {credentials.token}")
print(f"Refresh Token: {credentials.refresh_token}")
When you run the script, It will ask you to log in to your Gmail account and authorize the app in a browser window after running the script.
Copy the access_token and refresh_token for later use.
Google Console Cloud for Lambda Gmail Client project
To store Gmail credentials securely, use AWS Secrets Manager. To do this, follow these steps:
Go to AWS Console and select Secrets Manager.
Click on Store a new secret and select Choose Other Type of secret.
Copy and paste the following key-value pairs:
Click Next, enter the secret name as GmailOAuthSecrets and click on Store.
Remember the Secret ARN which will be used in Lambda.
AWS Secret Manager to Store Gmail OAuth Credentials
To notify users when email drafts are created, set up Amazon SNS. To do this, follow these steps:
AWS SNS topic for EmailDraftsCreated
Create an IAM Role for Lambda For Lambda to work, it requires permission to work with other AWS services.
Go to AWS Console and select IAM from the search.
Click on Roles and select Create role, then choose AWS Service and then Lambda.
Attach the following policies:
The role is named as LambdaEmailProcessor and then click create role.
LambdaEmailProcessor IAM Role
First check that Amazon Bedrock is turned on in us-east-1 region.
Go to Amazon Bedrock in the AWS Console.
In Model Access, enable Amazon Titan Text G1 - Premier or any other model you prefer.
Accept the access request.
This Lambda function will process emails, analyze sentiment, generate replies, and save drafts.
pip install boto3 google-auth-oauthlib google-auth-httplib2 google-api-python-client -t lambda_package/
Save the Lambda code (provided below) as lambda_package/lambda_function.py.
import json
import os
import boto3
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from google.auth.transport.requests import Request
import base64
import re
from googleapiclient.errors import HttpError
# AWS Clients
secrets_manager = boto3.client('secretsmanager')
comprehend = boto3.client('comprehend')
bedrock = boto3.client('bedrock-runtime')
sns = boto3.client('sns')
def extract_sender_name(sender_email):
"""
Extracts the sender's name from the email 'From' field.
Example:
- 'John Doe <john.doe@example.com>' → 'John Doe'
- 'john.doe@example.com' → 'John'
"""
match = re.match(r'(.+?)\s*<.*?>', sender_email)
if match:
return match.group(1).strip() # Extract name from 'John Doe <email>'
else:
return sender_email.split('@')[0].capitalize() # Fallback: Extract name from 'email@domain.com'
def lambda_handler(event, context):
try:
# Retrieve OAuth credentials from AWS Secrets Manager
secret_arn = os.environ['SECRET_ARN']
secret = secrets_manager.get_secret_value(SecretId=secret_arn)
secret_json = json.loads(secret['SecretString'])
creds = Credentials(
token=secret_json.get('access_token'),
refresh_token=secret_json['refresh_token'],
client_id=secret_json['gmail_client_id'],
client_secret=secret_json['gmail_client_secret'],
token_uri='https://oauth2.googleapis.com/token'
)
if creds.expired and creds.refresh_token:
print("Refreshing token...")
creds.refresh(Request())
secret_json['access_token'] = creds.token
secrets_manager.put_secret_value(SecretId=secret_arn, SecretString=json.dumps(secret_json))
print("Token refreshed")
# Build Gmail API client
service = build('gmail', 'v1', credentials=creds)
print("Gmail API client built")
# Fetch unread emails
results = service.users().messages().list(userId='me', labelIds=['UNREAD']).execute()
messages = results.get('messages', [])
print(f"Found {len(messages)} unread emails")
if not messages:
print("No unread emails found.")
return {'statusCode': 200, 'body': 'No unread emails'}
drafts_created = 0
for msg in messages:
message = service.users().messages().get(userId='me', id=msg['id'], format='full').execute()
headers = {h['name']: h['value'] for h in message['payload']['headers']}
subject = headers.get('Subject', 'No Subject')
sender = headers.get('From', 'Unknown Sender')
# Extract sender's name
sender_name = extract_sender_name(sender)
print(f"Extracted sender name: {sender_name}")
body_data = message['payload'].get('body', {}).get('data', '')
text = base64.urlsafe_b64decode(body_data).decode('utf-8', errors='ignore') if body_data else message.get('snippet', '')
print(f"Processing email from {sender}: {subject}")
print(f"Email content: {text}")
# Perform Sentiment Analysis
sentiment_response = comprehend.detect_sentiment(Text=text[:5000], LanguageCode='en')
sentiment = sentiment_response['Sentiment']
print(f"Sentiment: {sentiment}")
if sentiment in ['POSITIVE', 'NEGATIVE']:
# Enhanced AI Prompt for Titan Model
prompt = f"""
You are an AI email assistant drafting a professional reply to an unread email received by the user. You are replying as the recipient of the email to the sender, whose name is '{sender_name}'.
**Rules:**
- Maintain a **formal and professional tone**.
- Address the sender’s intent directly (e.g., respond to offers or questions).
- Do not include a greeting (e.g., 'Dear {sender_name}') or closing (e.g., 'Best regards')—focus only on the response body.
- Do not copy the sender’s words; write an original response.
- Adapt tone based on sentiment:
- If positive, keep it warm and appreciative.
- If negative, be empathetic and professional.
- Confirm interest in opportunities and ask about next steps if applicable.
**Email Received:**
From: {sender}
Subject: {subject}
Content:
---
{text[:1000]}
---
**Draft the response body:**
"""
try:
# Invoke Amazon Bedrock
bedrock_response = bedrock.invoke_model(
modelId='amazon.titan-text-lite-v1',
body=json.dumps({
"inputText": prompt,
"textGenerationConfig": {
"maxTokenCount": 300,
"temperature": 0.5,
"topP": 0.9
}
})
)
reply_body = json.loads(bedrock_response['body'].read())['results'][0]['outputText'].strip()
print(f"Generated AI Reply: {reply_body}")
except Exception as e:
print(f"Bedrock error: {str(e)}")
raise
# Check for any greeting or closing in the AI response (case-insensitive)
reply_body_lower = reply_body.lower()
greeting_patterns = [f"dear {sender_name.lower()}", f"hello {sender_name.lower()}", f"hi {sender_name.lower()}", "dear", "hello", "hi"]
closing_patterns = ["best regards", "sincerely", "kind regards", "thank you", "regards"]
reply_has_greeting = any(pattern in reply_body_lower for pattern in greeting_patterns)
reply_has_closing = any(pattern in reply_body_lower for pattern in closing_patterns)
# Add greeting and closing only if missing
if not reply_has_greeting:
reply_body = f"Dear {sender_name},\n\n{reply_body}"
if not reply_has_closing:
reply_body += "\n\nBest regards,\nYour Name"
try:
# Create draft email
draft_message = f"To: {sender}\nSubject: Re: {subject}\n\n{reply_body}"
draft = {
'message': {
'raw': base64.urlsafe_b64encode(draft_message.encode('utf-8')).decode('utf-8')
}
}
print(f"Creating draft: {draft_message}")
service.users().drafts().create(userId='me', body=draft).execute()
drafts_created += 1
print("Draft created successfully")
except HttpError as e:
print(f"Draft creation failed: {e}")
# Send SNS Notification
if drafts_created > 0:
sns.publish(
TopicArn=os.environ['SNS_TOPIC_ARN'],
Message=f"{drafts_created} new email drafts created. Please review in Gmail."
)
print("SNS notification sent")
return {'statusCode': 200, 'body': f'Processed {len(messages)} emails, created {drafts_created} drafts'}
except HttpError as error:
print(f"Gmail API error: {error}")
return {'statusCode': 500, 'body': f'Gmail API error: {error}'}
except Exception as e:
print(f"Error: {str(e)}")
return {'statusCode': 500, 'body': f'An error occurred: {str(e)}'}
Deploy the Code:
Compress/ZIP the lambda_package folder:
cd lambda_package
zip -r ../lambda_function.zip .
In the Lambda console, select the Code tab, click Upload from and select .zip file, and upload lambda_function.zip.
Set Environment Variables:
Go to Configuration; select Environment variables and click on Edit.
Add the following values:
SECRET_ARN: Your Secrets Manager ARN (from Step 2)
SNS_TOPIC_ARN: Your SNS topic ARN (from Step 3)
Click on save button.
Set Timeout:
Under Configuration, select the General configuration and click on Edit button then set the timeout to 5 minutes to accommodate processing multiple emails.
EmailAutoReplyProcessor Lambda
Amazon EventBridge for Gmail-AutoReply-Schedule
Review the final outputs of AutoResponder AI in your Gmail account at the end of the process.
Unread email in your inbox
AutoResponder AI created a draft
AI generated drafted email
These steps have been checked and you have successfully created AutoResponder AI, an AI-based email assistant that:
This is a secure, cost-effective, and fully customizable serverless solution. Get a better and more efficient way of working with emails with AutoResponder AI!
Enjoy!