sendblue-openclaw-relay: How a tiny Python bridge makes OpenClaw feel native in iMessage
A public webhook, a private WebSocket, and ffmpeg in the middle. This repo shows that chatbot UX is really a delivery problem dressed up as AI.

Open-source relay server that bridges SendBlue (iMessage API) to OpenClaw agents via WebSocket
- This relay is a presence layer, not just a transport, because it makes an OpenClaw agent feel like a real participant inside iMessage.
- The core trick is a single persistent WebSocket behind a public SendBlue webhook, which separates public delivery from private agent state.
- Voice-note support is the strongest signal of intent, because `audio.py` preserves iMessage-native behavior instead of treating media as an afterthought.
- The project is intentionally small and single-tenant, which makes it a sharp bridge for one conversation rather than a generic messaging platform.
The interesting thing about sendblue-openclaw-relay is not that it forwards messages. It makes an OpenClaw agent feel like it already belongs inside an iMessage thread. That means replies, typing indicators, reactions, and voice notes that arrive in the format a user expects, not just whatever a generic webhook can manage.
The last mile is where the product actually lives
Most AI demos stop at text generation. This repo cares about the final mile, where presence becomes product. SendBlue owns the public edge, the relay owns state, and OpenClaw stays private behind a persistent socket.
That description is honest about the scale. This is not a platform story. It is a relay story, one job, one channel, one connection. The broader OpenClaw ecosystem already treats messaging as the interface, so adding iMessage is less a novelty than a missing piece.
One public webhook, one private agent, one persistent connection
In main.py, the important decision is not speed. It is control. A single global WebSocket is guarded by a lock, so the relay only keeps one OpenClaw extension active at a time. If another connection arrives, the old one gets replaced instead of multiplying into a swarm.
That is a sharp design choice. It makes the bridge feel personal, not multi-tenant. The public webhook receives SendBlue events, the relay forwards them over the socket, and outbound agent messages go back through the SendBlue API wrapper in sendblue.py. The result is a small state machine with a very clear contract.
The key architectural decision: OpenClaw is messaging-first. Your AI agent lives inside the apps you already use.
Why voice notes are the real giveaway
Voice notes are where the project stops looking like glue code. Apple voice messages often arrive as .caf, and audio.py uses ffmpeg to convert them into .ogg with libopus. That matters because users do not experience file formats. They experience whether the message plays inline and feels like it came from the same thread as everything else.
This is the part most generic relays miss. Text is easy. Presence is harder. Media is where the native feel either survives or falls apart.
What this replaces
| Approach | What it gives you | What it costs |
|---|---|---|
| Mac-bound iMessage automation | Direct access to iMessage on one machine | Requires Apple hardware, local upkeep, and tends to feel brittle |
| Native OpenClaw channels | Cleaner first-party chat surfaces like Telegram and Slack | Works well elsewhere, but leaves iMessage unsolved |
| sendblue-openclaw-relay | iMessage delivery for a private OpenClaw agent over a persistent socket | Adds a third-party transport and stays intentionally single-tenant |
The real comparison is not text versus voice. It is public edge versus private state. This relay wins when you want iMessage without a Mac, a private agent without exposing your machine, and enough protocol fidelity that the conversation still feels continuous.
Built for a personal relay, not a platform
Projects like this are easy to underestimate because they are small. But small is the point. The relay does not try to become a universal messaging layer. It owns one channel, one connection, and one set of conversion rules, which is exactly why it can make iMessage feel native instead of merely supported.
That is also the broader pattern. Users want to own the identity, the number, and the conversation surface, while renting the transport layer where it makes sense. This repo is a neat example of that BYOC mindset in practice.