Voice agents can talk, but they can't email. They handle phone calls, take orders, and answer questions — then the conversation ends and the context disappears. No follow-up email. No calendar invite. No CRM update.
Bridging voice to email and calendar is a common integration challenge. You need to capture the voice agent's output, format it for email, authenticate with the right provider, and handle the send — all in real time while the caller is still on the line.
Nylas CLI makes this a subprocess call. Your voice agent framework (LiveKit, Vapi, Retell, or custom) captures the intent, and the CLI handles email delivery and calendar creation. No API client libraries, no OAuth plumbing, no SMTP config.
Architecture
┌──────────────┐ ┌──────────────┐ ┌─────────────┐
│ Voice Agent │────▶│ Python │────▶│ Nylas CLI │
│ (LiveKit/Vapi)│◀────│ Bridge │ │ (email/cal) │
└──────────────┘ └──────────────┘ └─────────────┘
│
┌────▼────┐
│ LLM │
│(compose)│
└─────────┘
Install Nylas CLI
brew install nylas/nylas-cli/nylas
nylas auth login
Full setup: Getting Started with Nylas CLI
Send a follow-up email after a voice call
The simplest integration. After your voice agent finishes a call, send a summary email:
import subprocess
def send_followup(to_email, caller_name, summary):
"""Send a follow-up email after a voice call."""
subject = f"Follow-up: Call with {caller_name}"
body = f"Hi {caller_name},\n\nThanks for calling. Here's a summary:\n\n{summary}\n\nBest regards"
subprocess.run([
"nylas", "email", "send",
"--to", to_email,
"--subject", subject,
"--body", body,
"--yes"
])
# After voice call ends
send_followup(
"alice@company.com",
"Alice",
"- Discussed Q2 timeline\n- Agreed on April 15 deadline\n- You'll send the spec by Friday"
)
Full email sending guide: Send Email from the Command Line
Schedule a meeting during a voice call
Caller says "Let's book a meeting for next Tuesday at 2pm." Your agent creates it:
def schedule_meeting(title, when, duration, participants):
"""Create a calendar event from voice agent context."""
cmd = [
"nylas", "calendar", "create",
"--title", title,
"--when", when,
"--duration", duration,
"--participants", ",".join(participants),
"--yes"
]
result = subprocess.run(cmd, capture_output=True, text=True)
return result.returncode == 0
# Voice agent captures: "Book a meeting with Bob next Tuesday at 2pm for 30 minutes"
schedule_meeting(
"Call follow-up with Bob",
"next tuesday 2pm",
"30m",
["bob@company.com"]
)
Calendar guides:
- Manage Google Calendar from the CLI
- Manage Outlook Calendar from the CLI
- Manage Calendar from the Terminal
Check availability by voice
"Am I free tomorrow afternoon?" Your agent checks and responds:
import json
def check_availability(from_time, to_time):
"""Check calendar availability."""
result = subprocess.run(
["nylas", "calendar", "list",
"--from", from_time, "--to", to_time, "--json"],
capture_output=True, text=True
)
events = json.loads(result.stdout) if result.returncode == 0 else []
return events
# Voice agent asks about tomorrow
events = check_availability("tomorrow 12pm", "tomorrow 6pm")
if not events:
response = "You're free tomorrow afternoon."
else:
titles = [e["title"] for e in events]
response = f"You have {len(events)} events: {', '.join(titles)}"
LiveKit integration example
A complete LiveKit voice agent that can email and schedule:
from livekit.agents import AutoSubscribe, JobContext, WorkerOptions, cli
from livekit.agents.voice_assistant import VoiceAssistant
import subprocess
import json
async def entrypoint(ctx: JobContext):
assistant = VoiceAssistant(
# ... your LLM and TTS config
)
@assistant.on("function_call")
async def on_function_call(call):
if call.name == "send_email":
subprocess.run([
"nylas", "email", "send",
"--to", call.args["to"],
"--subject", call.args["subject"],
"--body", call.args["body"],
"--yes"
])
return "Email sent."
elif call.name == "schedule_meeting":
subprocess.run([
"nylas", "calendar", "create",
"--title", call.args["title"],
"--when", call.args["when"],
"--duration", call.args.get("duration", "30m"),
"--yes"
])
return "Meeting scheduled."
elif call.name == "check_inbox":
result = subprocess.run(
["nylas", "email", "list", "--unread", "--limit", "5", "--json"],
capture_output=True, text=True
)
emails = json.loads(result.stdout)
summaries = [f"{e['from'][0]['email']}: {e['subject']}" for e in emails]
return "Your unread emails: " + "; ".join(summaries)
Read inbox by voice
"Do I have any unread emails?" or "What did Alice send me today?"
def get_unread_summary(limit=5):
"""Get a voice-friendly summary of unread emails."""
result = subprocess.run(
["nylas", "email", "list", "--unread", "--limit", str(limit), "--json"],
capture_output=True, text=True
)
emails = json.loads(result.stdout) if result.returncode == 0 else []
if not emails:
return "No unread emails."
summaries = []
for e in emails:
sender = e["from"][0].get("name", e["from"][0]["email"])
summaries.append(f"{sender} sent: {e['subject']}")
return f"You have {len(emails)} unread emails. " + ". ".join(summaries)
For provider-specific email reading:
Extract OTP codes by voice
Voice agents handling account verification can pull OTP codes:
def get_otp():
"""Get the latest OTP code for voice readback."""
result = subprocess.run(
["nylas", "otp", "get", "--raw"],
capture_output=True, text=True
)
if result.returncode == 0:
code = result.stdout.strip()
return f"Your verification code is {' '.join(code)}" # spell out digits
return "No verification code found."
Full OTP guide: Extract OTP Codes from Email
Record the call itself
Use the built-in notetaker if the voice call happens over Zoom/Meet/Teams:
nylas notetaker send --meeting-link "https://zoom.us/j/123456789"
Full guide: Record Zoom, Meet, and Teams from the CLI
Audit trail
Every action your voice agent takes through the CLI is logged:
nylas audit list --limit 20
# Shows: who did what, when, from which agent
Full guide: AI Agent Audit Logs
Full guide with Vapi, Retell, and custom framework examples: Connect Voice Agents to Email and Calendar
Related guides:
- Give Your AI Agent an Email Address
- Give AI Agents Email Access via MCP
- Build an LLM Agent with Email Tools
- Build an AI Email Triage Agent
- Email as Memory for AI Agents
- Why AI Agents Need Email
- Best CLI Email Tools Compared
All guides: cli.nylas.com/guides
Top comments (0)