自動SMSで費用対効果を最大化

April 21, 2026
執筆者
レビュー担当者

自動SMSで費用対効果を最大化

あなたの会社で、ユーザーを対象にした新しいSMSキャンペーンを開始すると想定してみてください。例えば、10万人規模のユーザーを対象に、150文字ほどのマーケティングメッセージを一斉送信するとします。当初は、10万セグメント分の費用を見込んでいました。しかし、実際に請求書を確認すると、想定の3倍もの金額が請求されていました。なぜ、こんなことになったのでしょうか? これは、マーケティング文の作成者が高額な送信コストの発生する絵文字やスマートクォートなどの特殊文字を使用したことが原因です。

リッチテキストやリッチコミュニケーションサービスを活用することで、マーケティングメッセージの訴求力は高まります。とはいえ、予算が限られている中小企業の場合、自動SMSマーケティングの請求書が届いて、思わぬ高額費用に驚くような事態は避けたいものです。たとえ大企業であっても、1円でも無駄なコストを抑える努力は欠かせません。では、一体なぜこのような事態が起きたのでしょうか。そして、どうすれば未然に防ぐことができるのでしょうか。ここからは、原因と具体的な対策について確認していきましょう。

SMS送信で思わぬ高額請求が発生する原因

なぜ絵文字や特殊文字を使うとSMSの料金が上がってしまうのか、その技術的な仕組みを説明します。

通常、テキストメッセージには、GSM-7エンコーディングが使用されます。テキストメッセージが開発された当初は、モバイルネットワーク経由で送受信できる文字として、128種類の英数字や記号に数値が割り当てられました。このような文字と数値の割り当てを「文字エンコーディング」と呼びます。

ただし、ここには注意すべき落とし穴があります。GSM-7ライブラリに含まれない文字(絵文字や非ラテン文字、スマートクォートなど)が1文字でも入ると、メッセージ全体が16ビットエンコーディングへ自動的に切り替わってしまいます。この方式の文字エンコーディングは、UCS-2と呼ばれます。意図せず使用してしまうと思わぬ問題を引き起こす可能性があります。

エンコーディングの方式がGSM-7からUCS-2に切り替わると、1件のメッセージを送るために必要なデータ量が増えます。Twilioは、SMSメッセージを分割(セグメント化)して送信します(「Twilio Segment」とは異なりますので、ご注意ください)。1セグメントあたりで送信できる文字数は、GSM-7は最大160文字、UCS-2は70文字までです。さらに、Twilioでは、分割されたメッセージを正しく復元できるよう、各セグメントの先頭に6バイトのユーザーデータヘッダーを付加します。そのため、実際にメッセージ本文として使える文字数は、GSM-7で最大153文字、UCS-2で最大67文字です。メッセージがこの上限を超えると、想定外の請求額になる場合があります。

注意が必要な文字の種類

この問題の潜在的な原因のひとつに、絵文字が挙げられます。絵文字は標準のGSM-7文字セットに含まれていないため、テキストメッセージで絵文字を送信すると、自動的にUCS-2エンコーディングに切り替わります。これはわかりやすく、比較的簡単に特定できます。しかし、SMSのエンコーディングが切り替わる原因には、一見すると気づきにくいものが他にもあります。

スマートクォートとアポストロフィ: Google Docsからコピー&ペーストを実行すると、文字列の前に入力されるスマートクォートが非標準文字として認識され、このエラーが発生する場合があります。スマートアポストロフィも同様です。これらの文字は、メッセージから削除しても相手は気づきませんが、削除し忘れると、請求額に大きな差が出る可能性があります。

ロングダッシュ: 厄介なのが、AIが生成するコミュニケーションで多用されるエムダッシュ(—)、つまりロングダッシュです。これを取り除かないままテキストメッセージで送信すると、思わぬ問題を引き起こす可能性があります。AIや自動修正機能はこの記号を多用しがちで、特に最新のツールを使用していると陥りがちなミスです。しかし、ロングダッシュをハイフンに置き換えるだけで文字数を削ることができます。

アクセント: アクセント記号にはさまざまな種類が存在します。英語以外の言語でコミュニケーションを取る場合、こうした記号を扱う頻度は高くなります。一部のアクセント記号(「é」など)はGSM-7に対応していますが、その他の記号(「â」など)が含まれると、UCS-2へ自動的に切り替わってしまいます。使いたい特殊文字が規格に準拠しているか不明な場合は、Twilioドキュメントに掲載されているGSM-7文字マップでご確認いただけます。

Twilioのツールを活用して問題を解決する

原因が分かったところで、次はどうすればこれを回避できるかを見ていきましょう。

コミュニケーションの内容をテストしてGSM-7への準拠を確認し、コストを抑える方法はいくつかあります。

最も簡単な対策は、Twilio Messaging Segment Calculatorを使って、送信前にメッセージをテストすることです。[送信]ボタンを押す前に本文をチェックすることで、送信に必要なセグメント数を事前に把握できます。

ここでは、テキストのみの基本的なSMSの例と、絵文字を追加することでメッセージのエンコード構造がどのように変化するかを紹介します。

Message Segment Calculator showing an SMS message in GSM-7.
Message Segment Calculator showing an SMS message in GSM-7.
Message Segment Calculator showing an SMS message in Unicode.
Message Segment Calculator showing an SMS message in Unicode.

Twilioには、トグルボタンで切り替え可能なSMS向けのスマートエンコーディング機能が備わっています。

これは、スマートクォートなど問題の原因になる文字を、GSM-7規格に準拠した文字に自動変換する機能です。Twilioの自動SMS機能でテキストメッセージを送信する際は、常時、この機能を利用できます。Messaging Calculatorのスクリーンショットに、[Smart Encoding](スマートエンコーディング)のトグルボタンが表示されています。

絵文字は削除しませんが、問題を引き起こしやすい特殊文字だけを取り除いてくれる機能です。ここでは、見落としやすい文字を使って、このトグル機能が実際にどのように動作するかをご紹介します。

スマートエンコーディングがない場合:

Unfortunately this SMS includes an EM dash and no smart encoding, so it's swapped to Unicode.
Unfortunately this SMS includes an EM dash and no smart encoding, so it's swapped to Unicode.

同じメッセージで、スマートエンコーディングが有効な場合:

With smart encoding, this is a GSM-7 message. Screenshot of that.
With smart encoding, this is a GSM-7 message. Screenshot of that.

結果は同じように見えますが、セグメントの長さは全く異なります。

Twilio Messaging Serviceでスマートエンコーディングを有効にするには、Twilioダッシュボードの該当する設定画面に移動してください。このタブにアクセスするには、まずMessaging Serviceを作成します。次に、以下のスクリーンショットを参考に[Content Settings](コンテンツ設定)を探します。[Smart Encoding](スマートエンコーディング)トグルボタンが[On](オン)に設定されていることを確認します。

Dashboard showing content settings
Dashboard showing content settings

プログラムによる手法

メッセージングサービスに完全に依存するのではなく、プログラムで事前に問題となる文字を削除するのも有効な方法の一つです。自動SMSに含まれる問題のある文字を修正するには、有効な方法が2つあります。1つは「置換」(特殊な文字を高額なコストが発生しない標準文字に置き換える方法)、もう1つは「計算」(コストの増加をユーザーに警告する方法)です。

GSM-7サニタイザーメソッド

「サニタイザー」メソッドの実装は、防御的プログラミングにおける定番の手法です。.NET 10環境で作業している場合、ReadOnlySpan<char>や高性能な文字列ビルダーといったC# 14機能を活用することで、処理スピードを低下させずに実装できます。他のコーディング言語を使用する場合も、これらの基本的な考え方やアプローチを踏まえ、ご自身のプロジェクトの仕様に合わせて、最適な形で導入してください。

プログラムで活用できるメソッド例を以下に紹介します。この手法では、コスト増の原因になりやすい代表的な文字を検索し、GSM-7準拠の標準文字に置換します。

using System;
using System.Text;
using System.Text.RegularExpressions;

public static class SmsSanitizer
{
   // Basic GSM-7 character set (simplified example)
   private const string GsmBasic = "@£$¥èéùìòÇ\nØø\rÅåΔ_ΦΓΛΩΠΨΣΘΞ ÆæßÉ !\"#¤%&'()*+,-./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà";
   public static string Sanitize(ReadOnlySpan<char> input)
   {
       // Use Span<char> for the buffer to avoid multiple allocations
       Span<char> output = stackalloc char[input.Length];
       int outputIdx = 0;
       foreach (char c in input)
       {
           char replacement = c;
           // Handle special characters with their GSM-7 safe equivalents
           if (c == '\u201C' || c == '\u201D') // Left and right double quotes
               replacement = '"';
           else if (c == '\'' || c == '\u2018' || c == '\u2019') // Single quotes and apostrophes
               replacement = '\'';
           else if (c == '\u2014' || c == '\u2013') // Em dash and en dash
               replacement = '-';
           // Add the character if it's in GSM-7 basic set, otherwise add the replacement or '?'
           if (GsmBasic.Contains(replacement))
           {
               output[outputIdx++] = replacement;
           }
           else
           {
               // If replacement isn't in GSM-7 either, use '?'
               output[outputIdx++] = '?';
           }
       }
       return new string(output[..outputIdx]);
   }
}

このメソッドは、Webhookやキャンペーン用コントローラーに直接組み込むことができます。

app.MapPost("/api/validate-sms", (string messageBody) => {
    var sanitized = SmsSanitizer.Sanitize(messageBody);
    var stats = GetMessageStats(sanitized);
    return Results.Ok(new {
        Original = messageBody,
        Sanitized = sanitized,
        EstimatedSegments = stats.Segments,
        EncodingUsed = stats.Encoding,
        PotentialSavings = "If this contained smart quotes, we just saved you money!"
    });
});

セグメントカウンターロジック

メッセージの送信前にユーザーに警告を表示したい場合は、エンコードがUCS-2に切り替わるかどうかを確認する必要があります。そのためには、Twilioが提供するような計算ツールを独自に作成し、正規表現(Regex)を使って特殊文字が含まれているかをチェックします。

以下の上限に注意してください:

  • GSM-7: 1セグメントで160文字、2セグメント以上で153文字(「セグメントヘッダー」で7文字使用)
  • UCS-2: 1セグメントで70文字、2セグメント以上で67文字(「セグメントヘッダー」で3文字使用)
public static (int Segments, string Encoding) GetMessageStats(string text)
{
    // Regex for characters NOT in the GSM-7 basic or extended sets
    // (Simplified for this example)
    bool isUcs2 = Regex.IsMatch(text, @"[^a-zA-Z0-9\s!""#\$%&'()\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^_\{\|\}\~¡£¥§¿äöñüàèéìòùò]");
    int limit = isUcs2 ? 70 : 160;
    int multiLimit = isUcs2 ? 67 : 153;
    if (text.Length <= limit) return (1, isUcs2 ? "UCS-2" : "GSM-7");
    int segments = (int)Math.Ceiling((double)text.Length / multiLimit);
    return (segments, isUcs2 ? "UCS-2" : "GSM-7");
}

この手法では否定の正規表現を使用します。つまり、あらかじめ指定された安全な範囲に含まれない文字をすべて特定します。こうすることで、安全な文字セット以外の文字が含まれているかどうかを判別することができます。迷ったときは、送信ボタンを押す前に必ず再確認しましょう。思わぬ高額請求を未然に防ぐことができます。

ここで紹介したメソッドはあくまで一例ですので、お使いの技術スタックに合わせて組み込む必要があります。なお、これらのメソッドは、.NET Consoleアプリをはじめ、Web APIやFlexプラグインのバックエンドなどで幅広く活用できます。Twilioの内部ツールだけでも、大半の用途には十分対応できますが、プログラムによるアプローチを取り入れることで、必要に応じて出力結果をより詳細にコントロールできるようになります。

まとめ

優れたコピーは簡潔であることが基本です。さらに、GSM-7規格に対応した文字セットを選べば、送信コストも抑えられます。文字数の計算方法を理解し、事前に送信セグメント数を把握しておけば、無駄なコストを削減でき、安心してキャンペーンを開始できます。

自動SMSに関するサポートが必要な場合や、SMSマーケティングについて詳しく知りたい方は、Twilioブログで関連リソースをご覧ください。

Twilioと共に、お客様の期待を超える最高のサービスを作り出しましょう。

Amanda Langeは、テクニカルコンテンツ専門の.NETエンジニア。C#や.NETプログラミングを活用した、画期的な開発手法を発信します。お問い合わせは、amlange [ at] twilio.comまでお願いします。

AI生成による要約
  • SMSに特殊文字を使用すると、エンコーディングがGSM-7からUCS-2に切り替わり、送信コストが増加するおそれがあります。
  • コスト増加の原因となりやすい主な文字として、絵文字、スマートクォート、ロングダッシュ、アクセント付き文字などが挙げられます。
  • Messaging Segment CalculatorやSmart EncodingなどのTwilioツールは、SMSのコスト効率を最適化するのに役立ちます。

この要約は、AIにより生成されました。