Files
praisonai-triage-agent[bot]andMervin Praison 6fd27d0ed7 feat: safe_print for examples to avoid cp1252 UnicodeEncodeError (fixes #231)
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]>
2026-07-27 09:04:48 +00:00

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())