Building an Automated Job Search Agent with Email Notifications
Learn to build a production-ready AI agent that automatically searches for jobs daily and sends personalized email notifications. Complete implementation with GPT web search, email automation, and scheduling.
What We'll Build
In this implementation guide, we'll create an intelligent job search agent that:
- Automatically searches for jobs using GPT's web search capabilities
- Filters results for recent postings (last 24 hours)
- Sends formatted email notifications with job details
- Runs on a daily schedule using Python scheduling
- Handles errors gracefully and logs activities
Architecture Overview
Our job search agent uses a simple, modular design with decorators to create reusable tools:
@search_tool
Decorator that adds job search capabilities
@email_tool
Decorator that adds email notification features
@schedule_tool
Decorator that adds daily scheduling
Why Decorators?
Decorators make our code modular and reusable. You can easily add these capabilities to any agent just by adding @search_tool, @email_tool, or @schedule_tool above your class.
Prerequisites & Setup
Before we start coding, make sure you have:
- Python 3.8+ installed
- OpenAI API key with GPT-4 access
- Email account for sending notifications (Gmail recommended)
- App password for your email account
Install Required Libraries
pip install openai schedule smtplib email python-dotenv
1. Search Tool Decorator
The search tool decorator uses Python's @ syntax to add job search capabilities to any class:
def search_tool(api_key):
"""Decorator that adds job search capabilities to any class"""
def decorator(cls):
cls._openai_client = OpenAI(api_key=api_key)
def search_jobs(self, job_title, location, num_results=10):
query = f"Find {num_results} recent job postings for '{job_title}' in {location}"
response = self._openai_client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": query}],
tools=[{"type": "web_search_preview"}],
max_tokens=1500
)
return response.choices[0].message.content
cls.search_jobs = search_jobs
return cls
return decorator
2. Email Tool Decorator
The email tool decorator adds email notification capabilities:
def email_tool(email, password, smtp_server="smtp.gmail.com"):
"""Decorator that adds email capabilities to any class"""
def decorator(cls):
cls._email = email
cls._password = password
cls._smtp_server = smtp_server
def send_email(self, to_email, subject, message):
msg = MIMEText(message)
msg['From'] = self._email
msg['To'] = to_email
msg['Subject'] = subject
with smtplib.SMTP(self._smtp_server, 587) as server:
server.starttls()
server.login(self._email, self._password)
server.send_message(msg)
return True
cls.send_email = send_email
return cls
return decorator
3. Schedule Tool Decorator
The schedule tool decorator adds daily scheduling functionality:
def schedule_tool(cls):
"""Decorator that adds scheduling capabilities to any class"""
def schedule_daily(self, time_str, method_name):
method = getattr(self, method_name)
schedule.every().day.at(time_str).do(method)
print(f"Scheduled {method_name} daily at {time_str}")
def run_scheduler(self):
try:
while True:
schedule.run_pending()
time.sleep(60)
except KeyboardInterrupt:
print("Scheduler stopped")
cls.schedule_daily = schedule_daily
cls.run_scheduler = run_scheduler
return cls
4. Building the CLI Job Agent
Now let's create our CLI job agent using the decorators. The agent will ask for job details interactively:
# Apply all three decorators to give our agent capabilities
@search_tool(api_key="your-openai-api-key")
@email_tool(email="your@email.com", password="your-app-password")
@schedule_tool
class JobAgent:
def __init__(self):
print("Welcome to JobAgent CLI!")
print("=" * 40)
def get_job_details(self):
"""Interactive CLI to get job search details"""
print("
Let's set up your job search:")
job_title = input("Enter job title (e.g., 'Data Scientist'): ").strip()
location = input("Enter location (e.g., 'New York, NY'): ").strip()
recipient_email = input("Enter your email for notifications: ").strip()
return job_title, location, recipient_email
def find_and_send_jobs(self, job_title, location, recipient_email):
"""Main method that finds jobs and emails them"""
print(f"
Searching for '{job_title}' jobs in {location}...")
print("Please wait while I search...")
# Use the search capability (from @search_tool)
jobs = self.search_jobs(job_title, location)
# Format the email
email_subject = f"Daily Jobs: {job_title} in {location}"
email_body = f"""
Here are today's fresh job postings:
{jobs}
---
Sent by your JobAgent CLI
Time: {datetime.now().strftime('%Y-%m-%d %H:%M')}
""".strip()
# Use the email capability (from @email_tool)
success = self.send_email(recipient_email, email_subject, email_body)
if success:
print("✓ Job search completed successfully!")
print(f"✓ Email sent to {recipient_email}")
else:
print("✗ Something went wrong with the email")
def start_cli(self):
"""Start the interactive CLI"""
while True:
print("
" + "=" * 40)
print("JobAgent CLI - What would you like to do?")
print("1. Search for jobs once")
print("2. Set up daily job search")
print("3. Exit")
choice = input("
Enter your choice (1-3): ").strip()
if choice == "1":
job_title, location, recipient_email = self.get_job_details()
self.find_and_send_jobs(job_title, location, recipient_email)
elif choice == "2":
job_title, location, recipient_email = self.get_job_details()
schedule_time = input("Enter daily search time (HH:MM format, e.g., 09:00): ").strip()
# Create a wrapper function for scheduling
def scheduled_search():
self.find_and_send_jobs(job_title, location, recipient_email)
# Use the schedule capability (from @schedule_tool)
self.schedule_daily(schedule_time, scheduled_search)
print(f"✓ Daily job search scheduled for {schedule_time}")
print("✓ Running initial search...")
self.find_and_send_jobs(job_title, location, recipient_email)
print("
Starting daily scheduler... Press Ctrl+C to stop")
self.run_scheduler()
elif choice == "3":
print("Thanks for using JobAgent CLI!")
break
else:
print("Invalid choice. Please enter 1, 2, or 3.")
5. Running Your CLI Agent
Create a simple main file to start your interactive CLI:
# main.py - Start your CLI job agent
from agent import JobAgent
def main():
# Create and start your CLI job agent
agent = JobAgent()
agent.start_cli()
if __name__ == "__main__":
main()
CLI Output Example
$ python main.py
Welcome to JobAgent CLI!
========================================
========================================
JobAgent CLI - What would you like to do?
1. Search for jobs once
2. Set up daily job search
3. Exit
Enter your choice (1-3): 1
Let's set up your job search:
Enter job title (e.g., 'Data Scientist'): Software Engineer
Enter location (e.g., 'New York, NY'): San Francisco, CA
Enter your email for notifications: john@email.com
Searching for 'Software Engineer' jobs in San Francisco, CA...
Please wait while I search...
✓ Job search completed successfully!
✓ Email sent to john@email.com
6. Setup and Installation
To set up and run your CLI job search agent:
# Install required packages
pip install openai schedule
# Update your API keys in the decorators (in your agent.py file)
# Run your interactive CLI agent
python main.py
Security Note
For Gmail, you'll need to create an "App Password" instead of using your regular password. Go to Google Account settings → Security → 2-Step Verification → App passwords.
CLI Features
- • Interactive job search setup
- • One-time job search with immediate email
- • Daily scheduled job searches
- • Real-time feedback and status updates
- • Easy to use menu-driven interface
Key Concepts Explained
Python Decorators
- Use @ symbol to apply functions to classes
- Add functionality without modifying original code
- Stack multiple decorators for combined features
- Reusable across different agent types
Modular Design
- Each tool is independent and testable
- Easy to add new capabilities
- Clean separation of concerns
- Extensible for other automation tasks
Conclusion
Congratulations! You've built your first AI agent using a clean, modular approach with decorators.
What You've Accomplished
- Created reusable tool decorators for search, email, and scheduling
- Built a modular job search agent that's easy to understand and extend
- Learned how to make AI agents that actually solve real problems
- Used modern Python patterns that make code clean and maintainable
What's Next?
The decorator pattern we used here can be applied to build all kinds of AI agents:
- Price monitoring agents for e-commerce
- Social media content agents
- News summarization agents
- Stock market analysis agents
- And many more!