
TL;DR: Transactional SMS requires precision, clarity, and trust, and you get 160 characters to deliver all three. These 10 rules for SMS messaging cover leading with the outcome, naming your brand, making the next step obvious, and keeping templates from breaking on missing data or a stray emoji. Each rule shows a weak and a better version of a real message, with character counts.
When a customer's package is out for delivery or their payment fails, SMS is often the first thing they see. It arrives in the same thread as messages from their family, which sets a high bar for clarity.
You get 160 characters. Unlike marketing messages, transactional SMS is not the place to be clever. It has to be clear, accurate, and obviously from you. Get it wrong and you get support tickets, spam reports, or a customer who ignores the next one.
Whether you send through Twilio, MessageBird, or Vonage, the same rules apply.
| Rule | What it means |
|---|---|
| 1. Lead with purpose | Open with the outcome, not a greeting |
| 2. Make your brand clear | Name yourself in the first few characters |
| 3. Respect the character limit | 160 in GSM-7, 70 the moment you add an emoji |
| 4. Make actions clear | State the action, the deadline, and the link |
| 5. Keep links trustworthy | Branded domain, at the end, always HTTPS |
| 6. Share just enough context | Enough to recognize the event, nothing sensitive |
| 7. Handle security scenarios | Brand, code, expiry, and a never-share warning |
| 8. Get the timing right | Send within minutes, respect quiet hours |
| 9. Always provide an escape route | A specific opt-out, plus a way to get help |
| 10. Build templates that never break | Fallbacks, encoding tests, idempotent retries |
Each rule below has the reasoning and the examples.
The golden rule: lead with the outcome. People want to know what happened, not read a greeting.
| Version | Message | Chars |
|---|---|---|
| Weak | Hi there! Hope you're having a great day. We wanted to let you know that your package is on its way! | 100 |
| Better | Acme: Package 48372 is out for delivery today, arriving by 8 PM. Track: acme.co/t/48372 | 87 |
The second version is 13 characters shorter and answers three questions the first one leaves open: which package, when, and where to check.
Teams resist this because they want personality in every message. Transactional SMS is not where personality pays off. During a security alert or a failed payment, people want information fast.
Nothing kills trust faster than an unknown number sending account information.
ALERTS: Your account was accessed from a new device. (52 characters) says nothing about who sent it. Acme: New sign-in to your Acme account from Chrome on Windows in Austin, TX. (76 characters) costs 24 more characters and covers who, what, and where.
Generic sender IDs like ALERTS sound official to the team that picked them and suspicious to everyone else. Use your brand name, and use the same one everywhere. Nobody should have to work out whether "PayPal" and "PP-ALERTS" are the same company. Registered sender IDs and short codes help too, since they are harder to spoof.
The 160-character limit is not arbitrary. It is what fits in one message under GSM-7, the default 7-bit encoding. Step outside that character set and the limit drops to 70.
| Encoding | When it applies | Chars in one message | Chars per segment when split |
|---|---|---|---|
| GSM-7 | Standard Latin letters, digits, common punctuation | 160 | 153 |
| UCS-2 | Any emoji, curly quote, or accented character outside GSM-7 | 70 | 67 |
Two details catch people out. A single emoji or a curly apostrophe copied out of a design doc switches the whole message to UCS-2, so a 120-character message silently becomes two segments. And a handful of characters ({ } [ ] ~ ^ \ | and €) live in the GSM-7 extension table, where each one counts as two. You can watch this happen in the SMS preview generator: paste in a draft, add a curly quote, and the segment count changes as you type.
Segments matter beyond cost. Split messages can arrive out of order or get reassembled inconsistently on older devices. Write digits instead of spelled-out numbers, put the most important fact first, and leave the link for last. See the SMS channel documentation for provider-specific behavior.
Most transactional messages need someone to do something. Say what, and say by when.
| Version | Message | Chars |
|---|---|---|
| Weak | Please verify your account soon. | 32 |
| Better | Acme: Verify your account by 5 PM CT to keep transfers active: acme.co/v/9f2 | 76 |
"Soon" is not a deadline, and the weak version gives no way to act. The longer message is the better one here: length is worth spending on a deadline, a consequence, and a path.
Use real urgency only. People can tell the difference between "Package requires signature by end of day" and "Act now!", and they discount the second one. Name the time zone, or use relative timing like "within 2 hours" so it reads correctly everywhere.
Sequences like this are easier to manage as a flow than as scattered send calls. With Courier Journeys you trigger the follow-up from what the user actually did, handle the time zone conversion, and keep the whole sequence in one place.
Links in SMS have to work and look legitimate, and generic shorteners fail the second test.
Acme: Confirm your payout details bit.ly/3xKq9Za (48 characters) is indistinguishable from a phishing attempt. Acme: Confirm your payout details at acme.co/payouts (52 characters) costs four characters and shows the recipient exactly where they are going.
A branded short domain stays concise and carries your name. Put the link at the end so a tap does not select surrounding text, and always use HTTPS.
Include enough for the recipient to recognize the event, and nothing that hurts if the phone is on a coffee table.
| Version | Message | Chars |
|---|---|---|
| Weak | Acme: Card 4111 1111 1111 1234 charged $84.20 at Blue Bottle Coffee, 1 Ferry Building, San Francisco, CA 94111. | 111 |
| Better | Acme: $84.20 charged to card ending 1234 at Blue Bottle Coffee. Not you? acme.co/dispute | 88 |
The weak version leaks a full card number and a street address to anyone glancing at the lock screen, and it still has no way to report a problem. Last four digits, amount, and merchant are enough to recognize a charge.
Use the names people recognize rather than internal identifiers. What counts as enough context changes by message type: delivery updates need place and time, security alerts need device and location, payments need amount and merchant.
Verification codes and security alerts are the most impersonated messages you send, so they have to teach as well as inform.
| Version | Message | Chars |
|---|---|---|
| Weak | Your code is 402913. | 20 |
| Better | Acme: 402913 is your sign-in code. It expires in 10 minutes. We will never ask you for it. | 90 |
The better version names the brand, states an expiry, and inoculates against the most common social-engineering script in one line.
Keep the tone plain. Alarming language makes people freeze or call support instead of acting. Specific device and location details help someone judge whether an alert is real, where a generic warning does not. Send codes and alerts immediately, since every minute of delay is a window.
A delivery notification that lands three hours late is worse than none, because it teaches people your messages are not current.
Send within minutes of the event. Then apply judgment: a payment confirmation at 3 AM is immediate and unwelcome, so hold non-urgent notifications until quiet hours end. Use each recipient's local time for every timestamp you print.
Watch cadence too. Every message in a sequence should carry new information, or it trains people to ignore the thread. And close the loop when something resolves, whether that is a security threat cleared or an outage restored. Resolution messages are the ones teams forget to build. The Delay node covers how to build waits into a sequence.
Every message needs a way out and a way to get help.
Reply STOP to unsubscribe. (26 characters) is the minimum. Acme alerts: reply STOP to end, HELP for help. Order updates continue. (70 characters) is better, because it tells people what they are actually turning off.
That distinction matters. Someone who wants fewer marketing texts rarely wants to stop receiving order confirmations, and a single blunt opt-out forces that choice on them. Per-topic preferences solve it properly. Whatever you offer, make sure the channel behind it works: staff the number, and handle replies. Opt-out requirements and data handling vary by country, so confirm what applies to the regions you send to. Courier's preference management handles per-topic control across channels.
Most SMS failures are template failures, and they show up in production rather than review.
Handle missing data. If a template expects a tracking number and the upstream system sends nothing, the message should still read correctly rather than shipping "Your package is out for delivery." Build a fallback for every variable.
Test the character set, not just the copy. A name with an accent, a curly apostrophe pasted from a doc, or an emoji in a user-supplied field flips the message to UCS-2 and can split it mid-word. Run the worst case through the SMS preview generator and you will see the split before a customer does. Formats matter the same way: 03/04 is two different dates depending on where the recipient lives.
Make retries idempotent so a network blip does not send three confirmations. And version your templates, so a change to shared copy does not break journeys that are already running. Variable fallbacks and locale handling live in Design Studio.
Lead with the outcome rather than a greeting, put your brand name in the first few characters, stay inside 160 characters, and state the action and its deadline explicitly. After that, the rules that matter most are link hygiene, sharing only the context the recipient needs, sending within minutes of the triggering event, and offering an opt-out specific enough that stopping marketing texts does not also stop order confirmations.
160 characters using GSM-7, the default 7-bit encoding. If the message contains any character outside that set, it switches to UCS-2 and the limit drops to 70. Longer messages are split into segments of 153 characters under GSM-7 or 67 under UCS-2, because each segment gives up space to reassembly headers. If you would rather not do that math by hand, the SMS preview generator counts segments as you type.
Emoji do not exist in GSM-7, so a single one forces the entire message into UCS-2 encoding, where the limit is 70 characters instead of 160. Curly quotes and accented characters do the same thing, which is why copying copy out of a design doc can silently double your segment count.
Yes, when the message asks for an action. Use a branded short domain rather than a generic shortener, since recipients cannot tell a shortened link from a phishing attempt, and place it at the end of the message so tapping it does not select the surrounding text.
The brand name, the code, an expiry window, and a line saying you will never ask for the code. That last part is what protects people against the most common social-engineering script, and it fits inside 160 characters.
Within minutes of the event that triggered it, since the value of a delivery or security notification decays quickly. Hold non-urgent messages such as receipts until quiet hours end in the recipient's local time zone.
Requirements vary by country and carrier, and transactional messages are usually treated differently from marketing. Include a clear opt-out anyway, and make it specific enough that stopping promotional texts does not also stop order confirmations. Confirm what applies to the regions you send to.
All 10 rules come down to discipline: one purpose per message, your name at the front, a deadline when there is one, and templates that survive real data.
Industry requirements sit on top of that. Appointment reminders and results in healthcare, security and subscription alerts in SaaS, order and shipping updates in a marketplace.
If you would rather not build the sending, preference, and template layers yourself, talk to an engineer about how Courier handles them.

The federal texting rule your transportation and logistics software is breaking
A single text to a driving trucker can trigger a federal fine of up to $11,000 for the motor carrier, and your transportation and logistics software is often what sent it. How to design driver notifications that stay on the right side of FMCSA rules.

How to Design an In-App Notification Center: UX tips and examples
A design-focused guide to building an in-app notification center people actually use. Covers the UX decisions that matter (entry point, information hierarchy, read state, grouping, empty states, inline actions, real-time, accessibility), then shows three ways to execute in Courier Inbox: brand-match with a theme, take over individual pieces with render props, or go fully headless with the `useCourier` hook. Ends with a pre-ship checklist.

How Apple's on-device AI works, and what it changes for your users
Apple's 2026 on-device models (AFM 3) are good enough to read, rank, and summarize everything that lands on your phone, locally and for free. Here's how they actually work, in plain terms, and how a model that reads every message before your users do changes what you should send.
© 2026 Courier. All rights reserved.