Návrh integrace O2 SMS Connector do Dynamics 365 (Dataverse)

Odesílání SMS z Dynamics 365 / Dataverse přes službu O2 SMS Connector pomocí Power Automate (varianta bez Azure a bez vlastního kódu pro mTLS).

Obsah


1. Cíl a kontext

Potřebujeme z Dynamics 365 (Dataverse) odesílat textové SMS koncovým uživatelům přes službu O2 SMS Connector. Řešení musí být:


2. Jak funguje O2 SMS Connector

Služba nabízí dvě rovnocenná rozhraní ke stejné platformě (O2 Messaging Platform, „MP"):

Rozhraní Vlastnosti Použití
HTTP GET/POST Jednoduché, jen textové SMS ✅ Doporučeno pro náš případ
Web Services (SOAP) Plná funkcionalita (binární SMS, MMS, push) Jen pokud bude potřeba více

Pro odesílání textové SMS použijeme HTTP POST na endpoint:

https://smsconnector.cz.o2.com/smsconnector/getpost/GP

Klíčové pojmy

Parametry akce send

Parametr Povinný Popis
action send
baID ID aplikace, např. 1991123
toNumber příjemce v mezinár. formátu +420602... (CZ = přesně 12 číslic vč. +420)
text text; max 160 znaků, nebo 900 při multipart=TRUE. Jen 7bit GSM 03.38 — bez diakritiky
msgID naše unikátní ID zprávy (doporučeno, kvůli párování delivery reportů; bez ;)
deliveryReport TRUE/FALSE (default FALSE)
multipart TRUE umožní text > 160 znaků (O2 účtuje každou část)
fromNumber odesílatel — baID, MSISDN nebo NICKNAME (musí být provisioned u O2)
validityPeriod platnost v sekundách, max 388800 (4,5 dne)
priority 1 VIP / 2 high / 3 normal (default)

Odpověď (HTTP 200, text/plain, UTF-8) je sada řádků KLÍČ=HODNOTA. Úspěch = responseType=SUCCESS, responseCode=ISUC_001. Synchronní chyby vrací HTTP 400. Naše msgID se vrací v poli refMsgID.


3. Jádro problému — klientský certifikát v sandboxu

O2 vyžaduje mutual TLS s klientským certifikátem. Plugin v Dataverse ale běží v sandboxu (isolation mode), který je pro práci s certifikátem prakticky nepoužitelný:

Co je potřeba k mTLS Stav v sandboxu
Načíst .pfx/.p12 ze souboru ❌ žádný přístup k file systému
Načíst cert z Windows cert store (X509Store) ❌ blokováno SecurityException
X509Certificate2 s privátním klíčem z byte[] ⚠️ potřebuje persistovat klíč na disk → selže; EphemeralKeySet je až .NET 4.7.2, plugin cílí na 4.6.2
Odchozí síť ✅ jen HTTP/HTTPS na portech 80/443

Další omezení: 2minutový timeout, žádná vlákna/registry/event log, synchronní volání externí služby blokuje transakci platformy.

Závěr: mTLS s klientským certifikátem přímo z pluginu Microsoft nepodporuje a v praxi to spolehlivě nezprovozníte. Certifikát musí žít mimo sandbox.

Řešení: Power Automate to umí nativně

Premium akce HTTP v Power Automate má v nastavení Authentication přímo typ Client Certificate, kde zadáte:

Connector provede mTLS handshake za vás. Žádný sandbox, žádný kód, žádné Azure.


4. Doporučená architektura — Outbox pattern

Plugin pouze vytvoří řádek v „outbox" tabulce (rychlé, sandbox-safe) a skončí. Power Automate Flow se spustí na vytvoření řádku, zavolá O2 přes mTLS a zapíše zpět stav.

flowchart LR subgraph DV["Dataverse / Dynamics 365"] BL["Business logika
(plugin / workflow)"] OB[("Tabulka
o2_smsmessage
(Outbox)")] BL -->|"1 - Create row
(Pending)"| OB end subgraph PP["Power Platform"] FLOW["Power Automate Flow"] end O2["O2 SMS Connector
HTTP POST /GP"] OB -.->|"2 - Trigger:
When a row is added"| FLOW FLOW -->|"3 - HTTP POST + mTLS
(Client Certificate)"| O2 O2 -->|"4 - responseCode
refMsgID"| FLOW FLOW -->|"5 - Update row
(Sent / Failed)"| OB

Proč outbox tabulka a ne trigger přímo na business entitě

Sekvenční pohled

sequenceDiagram participant U as Uživatel / proces participant P as Plugin (sandbox) participant OB as o2_smsmessage participant F as Power Automate Flow participant O2 as O2 SMS Connector U->>P: akce v Dynamics (např. vznik případu) P->>OB: Create row (status=Pending) P-->>U: transakce hotová (neblokuje) Note over OB,F: asynchronně, mimo transakci OB-->>F: trigger "When a row is added" F->>F: sestavení form body + URL-encode F->>O2: HTTP POST (Client Certificate / mTLS) O2-->>F: 200 OK, responseCode=ISUC_001, refMsgID F->>OB: Update row (status=Sent, kód, refMsgID)

5. Datový model — tabulka o2_smsmessage

Custom tabulka jako outbox a zároveň audit log.

Sloupec (logický) Typ Popis
o2_tonumber Text Příjemce +420...
o2_text Multiline text Text zprávy
o2_status Choice Pending (1), Sent (2), Failed (3)
o2_msgid Text Naše unikátní msgID (GUID)
o2_responsecode Text Návratový kód O2 (ISUC_001, EFMT_007, …)
o2_refmsgid Text refMsgID z odpovědi O2
o2_rawresponse Multiline text Surová odpověď O2 (pro diagnostiku)
o2_senton DateTime Čas odeslání
classDiagram class o2_smsmessage { +string o2_tonumber +string o2_text +choice o2_status (Pending/Sent/Failed) +string o2_msgid +string o2_responsecode +string o2_refmsgid +string o2_rawresponse +datetime o2_senton }

6. Plugin (sandbox-safe)

Plugin nedělá nic náročného — jen zapíše řádek do outboxu. Veškerá síťová a certifikátová logika je mimo sandbox.

var sms = new Entity("o2_smsmessage");
sms["o2_tonumber"] = "+420602123456";
sms["o2_text"]     = "Vas kod je 1234";
sms["o2_status"]   = new OptionSetValue(1); // Pending
service.Create(sms);

Plugin step registrujte tak, aby zápis odpovídal vaší business logice (typicky synchronně na hlavní entitě — samotný Create řádku je levný; vlastní odeslání SMS je už asynchronní díky flow).


7. Power Automate Flow

Kroky

  1. Trigger: Dataverse → When a row is added na tabulce o2_smsmessage.

  2. (Volitelně) Get Secret: Azure Key Vault → načtení Pfx Base64 a hesla, nebo čtení z Environment Variables.

  3. Compose – body (form-urlencoded; text musí být URL-enkódovaný):

text action=send &baID=@{variables('baID')} &toNumber=@{uriComponent(triggerOutputs()?['body/o2_tonumber'])} &text=@{uriComponent(triggerOutputs()?['body/o2_text'])} &msgID=@{guid()} &deliveryReport=FALSE &multipart=@{if(greater(length(triggerOutputs()?['body/o2_text']),160),'TRUE','FALSE')} &priority=3

(v praxi jako jeden concat() / Compose bez odřádkování)

  1. HTTP akce:
  2. Method: POST
  3. URI: https://smsconnector.cz.o2.com/smsconnector/getpost/GP
  4. Header: Content-Type: application/x-www-form-urlencoded
  5. Body: výstup z Compose
  6. Authentication: Client Certificate → Pfx (Base64), Password

  7. Vyhodnocení odpovědi — O2 vrací text/plain řádky KLÍČ=HODNOTA. Úspěch:

text contains(body('HTTP'), 'responseType=SUCCESS')

nebo přesněji vytáhnout responseCode (ISUC_001) a refMsgID.

  1. Update row v o2_smsmessage → status Sent/Failed, uložit responseCode, refMsgID a surovou odpověď.

Tok flow

flowchart TD T["Trigger: When a row is added
(o2_smsmessage)"] --> S["Get Secret
(Pfx Base64 + password)"] S --> C["Compose: form-urlencoded body
(uriComponent na text)"] C --> H["HTTP POST → O2
Auth: Client Certificate"] H --> Q{"responseType=SUCCESS?"} Q -->|Ano| OK["Update row:
status=Sent
responseCode, refMsgID"] Q -->|Ne| ERR["Update row:
status=Failed
rawResponse"]

8. Security a správa secrets

Secret Doporučené uložení
Pfx (Base64) + password Ne natvrdo do akce (viditelné v exportu flow). Použít Environment Variables typu Secret (ideálně s referencí na Azure Key Vault), nebo connector Azure Key Vault → Get Secret na začátku flow.
baID, endpoint Environment Variables (mohou referencovat Key Vault). Žádný hardcode.

Konverze certifikátu .p12 → Base64 (PowerShell):

[Convert]::ToBase64String([IO.File]::ReadAllBytes("cert.p12"))

9. Na co dát pozor

Téma Doporučení
Licence HTTP je premium connector → potřeba Power Automate per-flow/per-user plán. Ověřit licencování.
Retry na HTTP 403 Dle manuálu: opakovat po 5 s, max 5×. Nastavit na HTTP akci Settings → Retry Policy, nebo obalit do Do until.
Diakritika Jen 7bit GSM 03.38 — háčky/čárky O2 v AO směru nepodporuje. Před odesláním text transliterovat (odstranit diakritiku).
Delivery reporty Chodí asynchronně přes receive (jiný endpoint). Pokud je budete chtít, je to samostatný flow s plánovaným pollingem — k odeslání není potřeba.
Formát čísla CZ příjemce přesně 12 číslic vč. +420 (EFMT_007 při chybě).
Throttling Standardní kapacita 1 SMS/s; při překročení se send zpomalí. Vyšší kapacita (5/20 SMS/s) za příplatek.

10. Otevřené otázky pro zákazníka

Než finalizujeme implementaci, potřebujeme od zákazníka (a částečně od O2) zodpovědět níže uvedené otázky. Jejich odpovědi rozhodnou o volbě rozhraní a konkrétní metody (HTTP GET/POST vs Web Services, a v rámci WS SimpleSmsGw.sendSms vs PPGw.send, pull vs push). Náš návrh počítá s HTTP GET/POST přes Power Automate — to je správně jen pokud odpovědi nevynutí SOAP (viz rozhodovací matice).

Slouží zároveň jako checklist na schůzku — pole na odpovědi jsou prázdná.

A. Funkční rozsah (rozhoduje o rozhraní)

# Otázka Odpověď
A1 Směr komunikace — jen odchozí SMS (AO/MT), nebo i příchozí (MO/AT, odpovědi uživatelů, two-way)?
A2 Pokud i příchozí — pull, nebo push mode? (push = zákazník provozuje veřejný endpoint na portu 443/8443)
A3 Potřeba delivery reportů (potvrzení o doručení)? Co s nimi — logovat / reagovat?
A4 Posílat binární SMS / MMS / flash (intruder) SMS / premium (zpoplatněné) zprávy? (binary/MMS/premium = jen Web Services)
A5 Diakritika — stačí transliterace (odstranění háčků/čárek), nebo musí projít Unicode/UCS-2? (Unicode v AO jen přes Web Services)

B. Objem a kapacita (rozhoduje o tarifu)

# Otázka Odpověď
B1 Kolik SMS denně / měsíčně, jaké jsou špičky?
B2 Požadovaná propustnost — 1 / 5 / 20 SMS/s? (vyšší = příplatek, ovlivňuje throttling)
B3 Jsou potřeba paralelní vlákna (vyšší objem najednou)?

C. Identita a registrace u O2

# Otázka Odpověď
C1 Je už uzavřená smlouva / aktivovaná služba SMS Connector, nebo začínáme od nuly?
C2 Máte přidělené baID, nebo si chcete zvolit vlastní číslo?
C3 Na jaké hlasové číslo bude služba navázaná? (jeho deaktivace = deaktivace SMS Connectoru)
C4 SMS Connector vs SMS Connector Plus (rozšířená varianta) — co máte/chcete?

D. Certifikát

# Otázka Odpověď
D1 Veřejná CA (1.CA, Verisign…), nebo O2-generovaný certifikát?
D2 Kdo certifikát vygeneruje, kde bude uložený (Key Vault?) a kdo hlídá expiraci/obnovu?

E. Odesílatel a obsah

# Otázka Odpověď
E1 Jak se má SMS zobrazit příjemci — z baID, z konkrétního MSISDN, nebo jako alfanumerický NICKNAME? (NICKNAME vyžaduje zvlášť provisioning u O2)
E2 Délka zpráv — do 160 znaků, nebo multipart do 900? (multipart = O2 účtuje každou část)
E3 validityPeriod a priorita — jak dlouho se má O2 pokoušet doručit, VIP/high/normal?

F. Provoz

# Otázka Odpověď
F1 Existuje testovací baID / sandbox u O2 pro vývoj a testy?
F2 Vyžaduje O2 IP whitelisting vašeho prostředí?
F3 Kdo bude kontaktní osoba pro SMS Connector (vyřizuje dotazy příjemců)?

Rozhodovací matice

Mapování odpovědí na správnou metodu:

Odpovědi zákazníka Doporučená metoda
Jen odchozí textové SMS, bez Unicode diakritiky, bez delivery reportů HTTP GET/POST send ← náš návrh (Power Automate)
Odchozí + potřeba delivery reportů přes pull HTTP GET/POST send + samostatný receive flow
Potřeba Unicode diakritiky, binary SMS, MMS nebo premium Web Services PPGw.send(MessageContainer)
Maximálně jednoduché odeslání přes SOAP, vše ostatní default Web Services SimpleSmsGw.sendSms
Vysoký objem příchozích zpráv, nízká latence Web Services push (PushPPGw) — zákazník provozuje endpoint

Klíčové „rozbíječe" HTTP GET/POST řešení (kvůli kterým bychom museli na Web Services): potřeba Unicode diakritiky, binary/MMS/premium zpráv, nebo push příjmu. Pokud žádný nenastane, zůstává HTTP GET/POST + Power Automate jako nejjednodušší volba.


11. Předpoklady a registrace u O2

  1. Registrace aplikace u O2 — aktivační formulář, navázání na hlasové číslo, volba tarifu a kapacity, přidělení baID a denních/měsíčních limitů.
  2. Certifikát — vygenerovat (O2 aplikace nebo veřejná CA: 1.CA, Verisign…), veřejnou část (.PEM) zaslat O2 ke spárování s baID, privátní (.P12) si ponechat.
  3. Limity a kapacitu potvrdit s O2.

12. Reference na manuály

Stažené v adresáři docs/:

Soubor Obsah
01_WebServices_rozhrani_ENG.pdf SOAP/Web Services rozhraní (plná funkcionalita)
02_HTTP_GET_rozhrani_ENG.pdf HTTP GET/POST rozhraní (použito pro tento návrh)
03_Deployment_Specific_Parameters.pdf Konkrétní hodnoty timeoutů, limitů, URL
04_SMS_Connector_Plus_EMP_UserManWS.pdf SMS Connector Plus (rozšířená varianta)
05_Certifikaty_Manual.pdf Generování certifikátů

Zdroj dokumentace: https://www.o2.cz/podnikatele-a-firmy/volani/sms-connector