mirror of
https://github.com/MervinPraison/PraisonAIUI.git
synced 2026-11-10 03:31:29 -10:00
Add examples/python/_shared/console.py with safe_print/icon helpers that degrade emoji to ASCII on legacy Windows code pages (cp1252) instead of crashing, mirroring the CLI _supports_unicode/_icon pattern. Wire the helper into the high-severity gateway (16, 17, 18) and channel (20-23) examples so they start on default Windows PowerShell without PYTHONUTF8. Co-authored-by: Mervin Praison <[email protected]>
159 lines
5.9 KiB
Python
159 lines
5.9 KiB
Python
"""Example 19: Email Bot — Deploy an AI agent to your mailbox.
|
|
|
|
Unique Concept: Email as a messaging platform — IMAP polling + SMTP replies.
|
|
|
|
This example demonstrates how to use the EmailBot from the praisonai SDK
|
|
to monitor an inbox and respond to emails using an AI agent.
|
|
|
|
Features:
|
|
• EmailBot with IMAP polling (configurable interval)
|
|
• SMTP reply with proper thread headers (In-Reply-To, References)
|
|
• Auto-reply detection (prevents infinite loops)
|
|
• Custom subject-based commands (@bot.on_command)
|
|
• BotSessionManager for per-sender conversation history
|
|
• BotConfig for sender allowlists and rate limiting
|
|
|
|
Requires:
|
|
pip install praisonai[email] praisonaiagents
|
|
export OPENAI_API_KEY=sk-...
|
|
export [email protected]
|
|
export EMAIL_APP_PASSWORD=your_16_char_app_password
|
|
|
|
Optional:
|
|
export EMAIL_IMAP_SERVER=imap.gmail.com (default)
|
|
export EMAIL_SMTP_SERVER=smtp.gmail.com (default)
|
|
|
|
Run:
|
|
python app.py # Start email bot
|
|
python app.py --probe # Test connectivity only
|
|
"""
|
|
|
|
import asyncio
|
|
import os
|
|
import sys
|
|
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
|
from _shared.console import icon, safe_print
|
|
|
|
# ── Check prerequisites ─────────────────────────────────────────────
|
|
|
|
try:
|
|
from praisonai.bots import Bot, EmailBot
|
|
from praisonaiagents import Agent, BotConfig
|
|
SDK_OK = True
|
|
except ImportError:
|
|
SDK_OK = False
|
|
safe_print(f"{icon('⚠️', '[WARN]')} Missing dependencies. Install with:")
|
|
safe_print(" pip install praisonai[email] praisonaiagents")
|
|
sys.exit(1)
|
|
|
|
|
|
# ── Agent setup ─────────────────────────────────────────────────────
|
|
|
|
agent = Agent(
|
|
name="email_assistant",
|
|
instructions="""You are a professional email support assistant.
|
|
|
|
Guidelines:
|
|
- Read the email carefully and understand the request
|
|
- Reply concisely and professionally
|
|
- Use proper email etiquette (greeting, body, sign-off)
|
|
- If the question is unclear, ask for clarification
|
|
- Keep replies under 300 words
|
|
- Sign off as "AI Assistant"
|
|
""",
|
|
llm="gpt-4o-mini",
|
|
)
|
|
|
|
|
|
# ── Approach 1: Bot() wrapper (simplest) ────────────────────────────
|
|
|
|
async def run_simple():
|
|
"""Start email bot with automatic env var resolution."""
|
|
bot = Bot("email", agent=agent)
|
|
safe_print(f"{icon('📧', '[EMAIL]')} Starting email bot for: {os.getenv('EMAIL_ADDRESS', '(not set)')}")
|
|
safe_print(" Listening for new emails... (Ctrl+C to stop)")
|
|
await bot.start()
|
|
|
|
|
|
# ── Approach 2: Direct EmailBot with config + handlers ──────────────
|
|
|
|
async def run_with_handlers():
|
|
"""Start email bot with custom handlers and configuration."""
|
|
config = BotConfig(
|
|
polling_interval=30.0,
|
|
max_message_length=10000,
|
|
session_ttl=86400, # 24h session TTL
|
|
allowed_users=[], # Empty = allow all senders
|
|
metadata={"imap_folder": "INBOX"},
|
|
)
|
|
|
|
bot = EmailBot(
|
|
token=os.environ.get("EMAIL_APP_PASSWORD", ""),
|
|
agent=agent,
|
|
config=config,
|
|
email_address=os.environ.get("EMAIL_ADDRESS", ""),
|
|
)
|
|
|
|
# Log every incoming email
|
|
@bot.on_message
|
|
async def log_email(message):
|
|
subject = message.metadata.get("subject", "(no subject)")
|
|
safe_print(f"{icon('📨', '[MSG]')} From: {message.sender.username}")
|
|
safe_print(f" Subject: {subject}")
|
|
safe_print(f" Preview: {message.text[:100]}...")
|
|
|
|
# Custom command: emails with subject starting with "/status"
|
|
@bot.on_command("status")
|
|
async def handle_status(message):
|
|
await bot.send_message(
|
|
channel_id=message.sender.user_id,
|
|
content={
|
|
"subject": "Re: Bot Status Report",
|
|
"body": (
|
|
f"🤖 Email Bot Status\n\n"
|
|
f"• Running: {bot.is_running}\n"
|
|
f"• Emails processed: {bot._emails_processed}\n"
|
|
f"• Platform: {bot.platform}\n"
|
|
f"• Email: {bot._email_address}\n"
|
|
),
|
|
},
|
|
reply_to=message.message_id,
|
|
)
|
|
|
|
safe_print(f"{icon('📧', '[EMAIL]')} Starting email bot with custom handlers")
|
|
safe_print(f" Email: {bot._email_address}")
|
|
safe_print(f" Poll interval: {config.polling_interval}s")
|
|
safe_print(f" Allowed senders: {'all' if not config.allowed_users else config.allowed_users}")
|
|
safe_print(" Listening... (Ctrl+C to stop)")
|
|
await bot.start()
|
|
|
|
|
|
# ── Probe: Test connectivity without starting ───────────────────────
|
|
|
|
async def run_probe():
|
|
"""Test email server connectivity."""
|
|
bot = Bot("email", agent=agent)
|
|
safe_print(f"{icon('🔍', '[PROBE]')} Testing email server connectivity...")
|
|
result = await bot.probe()
|
|
|
|
safe_print(f"\n Connection: {icon('✅', '[OK]') + ' OK' if result.ok else icon('❌', '[FAIL]') + ' FAILED'}")
|
|
safe_print(f" Platform: {result.platform}")
|
|
if result.bot_username:
|
|
safe_print(f" Email: {result.bot_username}")
|
|
if result.elapsed_ms:
|
|
safe_print(f" Latency: {result.elapsed_ms:.0f}ms")
|
|
if result.error:
|
|
safe_print(f" Error: {result.error}")
|
|
|
|
|
|
# ── Main ────────────────────────────────────────────────────────────
|
|
|
|
if __name__ == "__main__":
|
|
if "--probe" in sys.argv:
|
|
asyncio.run(run_probe())
|
|
elif "--handlers" in sys.argv:
|
|
asyncio.run(run_with_handlers())
|
|
else:
|
|
asyncio.run(run_simple())
|