MMS Handling
MMS (Multimedia Messaging Service) is the protocol for sending images, audio, video, and other attachments via the carrier messaging network. From a SignalWire developer's perspective MMS is sent the same way as SMS — you just add a MediaUrl parameter. Underneath, carrier transcoding, file-size limits, and message ID handling are noticeably different.
When to use MMS vs SMS
- Use SMS for text-only confirmations, OTP codes, reminders, opt-in/opt-out flows.
- Use MMS for receipts, before/after photos, product images, vCards, short voice clips, signed agreements (PDF rendered as image), promotional graphics.
- Use a link to a hosted asset when the asset is larger than 1 MB, when delivery reliability matters more than inline preview, or when you need analytics on view rates.
File size and format limits
Carrier limits dominate. SignalWire's outbound limit is 5 MB, but most US carriers reject anything above 1.2 MB. Practical safe target: 600 KB.
| Carrier | Practical inbound limit | Practical outbound limit | |---|---|---| | Verizon | 1.2 MB | 600 KB | | AT&T | 1.0 MB | 600 KB | | T-Mobile | 1.5 MB | 800 KB | | US Cellular | 1.0 MB | 500 KB | | iMessage (Apple) | 100 MB | 100 MB (but only between iMessage users) |
When in doubt, send 600 KB or less. Anything over is transcoded down to 600 KB or rejected.
Supported MIME types
| Type | MIME | Notes |
|---|---|---|
| Image | image/jpeg, image/png, image/gif | GIFs animate on most modern phones |
| Audio | audio/mpeg, audio/mp4, audio/wav | Often transcoded to AMR |
| Video | video/mp4, video/3gpp | Often transcoded to 320x240 |
| Contact | text/x-vcard, text/vcard | Renders as "Add contact" button on most clients |
| SMIL | application/smil | Slideshow layout — rare, mostly legacy |
PDFs are not natively supported in MMS. Render the first page as PNG and send that, or send a link.
Sending MMS via SignalWire LaML
import requests
PROJECT = "your-project-id"
TOKEN = "your-auth-token"
SPACE = "your-space.signalwire.com"
response = requests.post(
f"https://{SPACE}/api/laml/2010-04-01/Accounts/{PROJECT}/Messages.json",
auth=(PROJECT, TOKEN),
data={
"From": "+12125551111",
"To": "+13105552222",
"Body": "Here's the photo you requested.",
"MediaUrl": "https://cdn.example.com/photo.jpg",
},
)
For multiple media items, pass MediaUrl repeatedly:
data = [
("From", "+12125551111"),
("To", "+13105552222"),
("Body", "Before and after"),
("MediaUrl", "https://cdn.example.com/before.jpg"),
("MediaUrl", "https://cdn.example.com/after.jpg"),
]
Max 10 media items per message on SignalWire. Most carriers cap at 4 displayed inline; the rest may render as attachments.
Sending MMS via REST
The same parameters work on the SignalWire REST API:
curl -X POST https://{space}/api/laml/2010-04-01/Accounts/{project}/Messages.json \
-u "${PROJECT}:${TOKEN}" \
-d "From=+12125551111" \
-d "To=+13105552222" \
-d "Body=Here's the photo" \
-d "MediaUrl=https://cdn.example.com/photo.jpg"
Receiving MMS
Webhook URL configured on the phone number fires for both SMS and MMS. The webhook receives:
| Parameter | Type | Notes |
|---|---|---|
| From, To, Body | string | Same as SMS |
| NumMedia | int | Number of media attachments (0 for text-only SMS) |
| MediaUrl0, MediaUrl1, ... | URL | Signed URLs for each attachment, expire after 24 hours |
| MediaContentType0, ... | MIME | Content type of each attachment |
Fetch each MediaUrl with the SignalWire credentials and move the asset to your own storage immediately — the signed URLs expire.
import requests
num_media = int(form["NumMedia"])
for i in range(num_media):
url = form[f"MediaUrl{i}"]
content_type = form[f"MediaContentType{i}"]
response = requests.get(url, auth=(PROJECT, TOKEN))
# Save response.content to your own storage
A2P 10DLC and MMS
MMS sent to US numbers requires the same A2P 10DLC campaign registration as SMS. The campaign use case applies — there is no separate "MMS campaign" tier. Throughput limits include MMS in the messages-per-second budget.
Toll-free MMS does not require TCR registration but is subject to Toll-Free Verification (TFV). Unverified toll-free MMS is heavily rate-limited and may be blocked entirely on T-Mobile.
Cost model
MMS costs more than SMS per segment:
| Channel | SMS outbound | MMS outbound | |---|---|---| | 10DLC | ~$0.0079 / segment | ~$0.0200 / message | | Toll-free | ~$0.0090 / segment | ~$0.0225 / message | | Short code | ~$0.0049 / segment | ~$0.0150 / message |
Pricing accurate as of 2025-11. Check the current SignalWire pricing page for live rates. SMS is billed per 160-character segment; MMS is billed per message regardless of size.
Common failure modes
| Symptom | Cause | Fix |
|---|---|---|
| Image arrives blurry or pixelated | Carrier transcoded to low resolution | Pre-size to 640×480 max, JPEG quality 80% |
| GIF arrives as still image | Carrier dropped animation frames | Use very short GIFs (under 10 frames, 2 seconds) |
| MMS not delivering to some carriers | File over 1 MB | Compress to 600 KB |
| MMS delivers as SMS with link | Recipient on a non-MMS plan or feature phone | Fall back to SMS + link automatically |
| Inbound MMS missing | Webhook only checking Body, not NumMedia | Read NumMedia and iterate MediaUrl* |
| Recipient on iPhone shows green bubble | RCS/iMessage not engaged, MMS fell through | Expected — MMS is the green-bubble path |
Group MMS
Sending to multiple recipients with a shared media attachment creates a group MMS. Most carriers support up to 10 recipients per group MMS. Replies go to all participants.
data = {
"From": "+12125551111",
"To": "+13105552222,+14155553333,+16175554444",
"Body": "Team update",
"MediaUrl": "https://cdn.example.com/photo.jpg",
}
Use group MMS sparingly — replies fan out to all members, which surprises recipients and can trigger spam complaints.
Related patterns
- SMS best practices — opt-in, opt-out, segment math
- A2P 10DLC campaign registry — TCR registration
- Toll-free and hosted messaging — non-TCR alternative
- RCS messaging — the modern MMS replacement
References
- 3GPP TS 23.140 — Multimedia Messaging Service (MMS) functional description
- RFC 4356 — Mapping Between the SDP Bandwidth Modifiers
- SignalWire docs — Messaging API, MediaUrl parameter