Skip to content
Skip to the article
In Odoo: 7 articles
Odoo

Set up two-way SMS in Odoo with Twilio

Install and configure the Twilio gateway for Odoo 18 so SMS and MMS conversations thread into Discuss, and mirror core and marketing SMS into the same threads.

Updated
Applies to
  • Odoo 18.0
  • OCA mail_gateway 18.0
  • Twilio Programmable Messaging
Tags
  • odoo
  • twilio
  • sms
  • discuss
Reading time
10 min

This document covers installing and configuring mail_gateway_twilio, which gives Odoo two-way SMS and inbound MMS through Twilio, and its companion mail_gateway_twilio_sms_mirror, which copies Odoo's own outbound SMS into the same conversations. Use it when you want customers to text a number and have your team answer from Discuss.

Both modules are in the avunu-odoo-addons repository and target Odoo 18. For the module-selection approach behind them, see Odoo Community and OCA Overview.

How it works

Twilio posts every inbound text to a webhook on your Odoo server. Odoo finds or creates a Discuss channel for the sender's phone number and posts the message there. When someone replies in that channel, Odoo calls the Twilio Messages API and sends an SMS.

  • One channel exists per gateway and phone number, so all correspondence with a contact stays in one thread.

  • An inbound number is matched against the mobile and phone fields on contacts. A match makes the contact the message author. No match creates an Odoo guest named after the sender's Twilio profile name if present, otherwise the number.

  • Everyone listed under the gateway's Members tab sees every thread. In practice this is a shared team inbox.

  • Twilio delivery status callbacks update the message notification in Odoo.

Prerequisites

You need the following before you start.

  • Odoo 18 with the OCA mail_gateway module available in your addons path. mail_gateway_twilio depends on it, and on Odoo's phone_validation module.

  • A Twilio account with an SMS-capable number, or a Messaging Service that contains one. In the US, carriers require A2P 10DLC registration for application-to-person traffic. That registration happens in Twilio and is outside this module.

  • Your Twilio Account SID (starts with AC) and Auth Token, both shown in the Twilio console.

  • A public HTTPS URL for Odoo, because Twilio must be able to reach the webhook.

Install the modules

Add both module folders from the repository to your addons path, update the apps list, and install Mail Twilio Gateway. Install Twilio Gateway - SMS Mirror only if you want the mirror described below.

From the command line, for a database named <DATABASE>:

odoo-bin -d <DATABASE> -i mail_gateway_twilio,mail_gateway_twilio_sms_mirror --stop-after-init

Prepare Odoo for the webhook

Twilio signs each request using the exact URL it called. Odoo rebuilds that URL from the web.base.url system parameter, so the two must match character for character.

  1. Set the system parameter web.base.url to your public HTTPS address, for example https://odoo.example.com, with no trailing path.

  2. Enable proxy mode in your Odoo configuration if Odoo sits behind a reverse proxy:

[options]
proxy_mode = True

Warning

If web.base.url does not match the URL Twilio calls, every inbound message fails signature validation and is silently dropped. This is the most common setup mistake.

Create the gateway

Open the gateway list under Settings, Technical, Email, Gateway (this menu needs developer mode) and create a record with the type Twilio. The module reuses generic gateway fields for Twilio credentials, so the mapping is not obvious from the labels.

Gateway fieldWhat to enter
TokenYour Twilio Account SID (AC...)
Webhook SecretYour Twilio Auth Token
Webhook KeyAny random string you choose
Twilio From NumberYour Twilio number in E.164 format, such as +15551234567
Messaging Service SIDOptional, starts with MG

Notes on these fields:

  • The Webhook Secret is required. Odoo uses it for API authentication and to validate the X-Twilio-Signature header on inbound requests.

  • The Webhook Key becomes the secret segment of the inbound URL. Treat it like a password and pick something long and random.

  • Set either the From Number or the Messaging Service SID. If you set both, the Messaging Service wins, and the From Number is ignored. The module's own guidance is to prefer a Messaging Service for US A2P 10DLC traffic.

Add the users who should read and answer conversations on the Members tab, then save.

Register the webhook

Press Integrate Webhook on the gateway. Odoo tries to register the inbound URL in Twilio for you:

  • With a Messaging Service SID, it sets the service's inbound request URL (method POST).

  • With only a From Number, it looks the number up on your account and sets the number's SMS URL (method POST). If the number is not found on the account, registration fails.

If registration fails, for example because the credentials lack API permission, Odoo logs a warning and still marks the gateway as integrated. In that case register the URL by hand:

  1. Copy the Webhook Url shown on the gateway form. The Twilio module makes this field visible without developer mode.

  2. Paste it into the A message comes in field for your number in the Twilio console, with the method set to HTTP POST. For a Messaging Service, use its inbound settings instead.

The URL has this shape:

https://odoo.example.com/gateway/twilio/<WEBHOOK_KEY>/update

The route accepts only POST requests with form-encoded bodies, which is what Twilio sends. It always answers with an empty 200 response and no TwiML, so Twilio never sends an automatic reply. Problems are written to the Odoo log, not returned to Twilio.

The same URL doubles as the status callback for outbound messages. Odoo sends it with each message so Twilio reports delivery progress back.

Send and receive messages

Receive

Inbound texts appear in Discuss as a channel named after the sender's Twilio profile name if one is supplied, otherwise their phone number. A text with no body and no media is ignored.

Picture and other media messages (MMS) arrive as attachments. Odoo downloads each file from Twilio using your credentials and names it after the message SID. Audio attachments are flagged as voice notes so Discuss treats them as voice notes.

Reply in Discuss

Open the channel and type. Odoo converts the message to plain text and sends it through Twilio from your From Number or Messaging Service. When Twilio accepts the message, the notification shows as sent and stores the Twilio message SID.

Send from a contact

The module adds a Send SMS action to the contact form. It opens a small wizard with a message box and the name of the phone field to use, which defaults to mobile. If you have exactly one Twilio gateway, it is selected automatically. Otherwise the wizard asks which gateway to send from.

The number is normalized to E.164 before sending. If it cannot be normalized, you see the error "The phone number could not be formatted to E.164", so fix the contact's number first.

Send from automation

The module adds a Twilio SMS option to server actions, which you can use from automated actions. Configure it with these fields:

  • Twilio gateway: which gateway sends the message.

  • Partner Expression (optional): an inline expression that returns the recipient partner ID, such as object.partner_id.id. Without it, Odoo uses the record's own partner_id, or the record itself on contacts.

  • Number Field: the partner field that holds the phone number. It defaults to mobile.

  • SMS Body: the message text, with inline placeholders such as {{ object.name }}.

The action works only on models that use the chatter (mail.thread) and skips records that have no recipient partner. Each message is posted into the contact's channel, so automated messages and human replies share one history.

Delivery status

Twilio status callbacks update the notification on the message. A delivered status marks it sent. A failed or undelivered status marks it as an exception and records the Twilio error code and message, which are stored as the failure reason on the notification.

Mirror core and marketing SMS into Discuss

Odoo's built-in SMS features (notification texts and SMS Marketing) know nothing about gateways. Without the mirror, a customer's reply to one of those messages lands in a thread that never shows the original text. mail_gateway_twilio_sms_mirror fixes this by copying each successfully submitted outbound SMS into the recipient's Twilio thread.

The mirror is display only. It posts a copy into the channel without sending anything through Twilio, so it cannot create duplicates or loops. Delivery status for the original message stays with Odoo's own SMS records, and a marketing blast is not linked back to its campaign record. Failed messages are not mirrored. If mirroring itself fails, Odoo logs a warning and the original SMS is unaffected.

The module depends on Odoo's sms module. SMS Marketing is optional.

Choose the target gateway

For each SMS, Odoo picks a gateway in this order:

  1. A Twilio gateway whose webhook user is the author of the SMS. This supports per-user numbers and applies to notification SMS only.

  2. The Twilio gateway with Mirror outbound SMS here ticked for that company.

  3. Failing that, the first Twilio gateway found for that company.

Use one mirror target per company, and tick Mirror outbound SMS here on it whenever you have more than one Twilio gateway, so the choice is not left to the third rule. Gateways with no company set are also eligible.

Warning

Replies reach the mirrored thread only if the number Odoo's core SMS sends from is the same number behind the target gateway. If they differ, replies arrive on a different gateway and thread there.

Limitations

  • No outbound MMS. Twilio needs a publicly reachable media URL, and Odoo attachments are not public. Inbound MMS works.

  • Plain text only. Rich formatting is stripped before sending.

  • Shared visibility. Members of a gateway see all of its threads. For private per-user conversations, give each user their own Twilio number and create one gateway per number with that user as the only member. This needs configuration only, not code.

  • Rotating the Auth Token requires updating the gateway's Webhook Secret, because that field is both the API password and the signature key.

Troubleshooting

Inbound failures never reach Twilio as errors, so start with the Odoo log. These are the warnings the module writes:

Log message starts withMeaning
Twilio gateway not found for webhook_keyThe URL's key does not match a gateway, or the gateway is not in the integrated state. Press Integrate Webhook and compare the URL.
Twilio signature verification failed for webhook_keyThe signature did not match. Check web.base.url, proxy mode, and that the Webhook Secret is the current Auth Token.
Twilio webhook auto-registration failed for gatewayOdoo could not set the URL in Twilio. Set it manually in the console.

Other common problems:

  • Nothing arrives and the log is quiet. Confirm the inbound URL in Twilio matches the one on the gateway form, and that your reverse proxy forwards /gateway/twilio/ to Odoo.

  • Messages send but never show as delivered. The status callback uses the same URL, so the same signature checks apply. Fix those first.

  • Sending fails. The failed notification stores the error text as its failure reason. Verify the Account SID, Auth Token, and that the From Number belongs to the account.

  • Replies to marketing texts appear in the wrong place. Check the mirror target and number match described above.

Sources

This article is in the public domain (CC0 1.0), code samples included. Use it however helps you.