LiveKit's voice agent stack is the default choice for building production voice AI — Pipecat integrations, turn-taking, interruption handling, the full stack. It handles the voice layer brilliantly. What it doesn't handle is the moment at the end of the call when the agent says "I'll send you a confirmation email" or "I've booked a demo for Tuesday — check your inbox."

Why voice agents need email

Voice is stateless and transient. Customers can't re-play your agent's words. They want confirmations, summaries, receipts, and follow-ups in text. Email is the universal receipt channel — and it's where the rest of the customer's workflow lives.

The integration in practice

from livekit.agents import Agent, AgentSession, function_tool
from lumbox import Lumbox

lumbox = Lumbox(api_key=os.environ["LUMBOX_API_KEY"])
AGENT_INBOX_ID = os.environ["AGENT_INBOX_ID"]  # provisioned once

class VoiceAgent(Agent):
    def __init__(self):
        super().__init__(
            instructions="You are a demo-booking agent. Confirm details by voice, then email the summary."
        )

    @function_tool
    async def send_confirmation(self, to: str, summary: str) -> str:
        """Email a call summary to the caller."""
        msg = lumbox.inboxes.send(
            inbox_id=AGENT_INBOX_ID,
            to=to,
            subject="Your demo is booked",
            text=summary,
        )
        return f"Email sent: {msg.id}"

Inbound too: handling replies

Once the agent sends a confirmation, the customer might reply. Lumbox's webhooks push the parsed reply back to your runtime, and you can route it to a follow-up voice session, a CRM, or a human.

One shared inbox vs. per-caller inbox

For most voice agents, one persistent inbox (booking@youragent.com) is the right model — brand continuity, searchable history. Use per-caller inboxes only when you're running isolated agent personas or verifying the caller via OTP mid-call. lumbox.co supports both with the same API.