Appearance
Channel Guides
This page documents channel-specific behavior and common development notes.
Email
Flow
EmailChannelvalidates the payload type.- Creates one
NotificationRequest. - Creates one
NotificationDeliveryperTorecipient. - Resolves an active email channel config.
- Renders the email body.
- Creates a provider through
EmailProviderFactory. - Sends through SMTP or Azure Graph.
Providers
| Provider | Enum | Notes |
|---|---|---|
| SMTP | EmailProviders.SMTP | Uses MailKit. Optional username/password authentication. |
| Azure Graph | EmailProviders.AzureGraph | Uses Microsoft Graph client credentials and sends from SenderIdentity. |
Template Rendering
If TemplateData is supplied:
- the service loads
{TemplateName}.htmlor{TemplateName}_ar.html - Arabic falls back to English when the Arabic template file does not exist
- scalar placeholders can be replaced by property name
{{#each CollectionName}}...{{/each}}loops are supported for simple collections
If UseSharedLayout is true, the rendered body is inserted into EmailLayoutTemplate.
Best Practices
- Keep email payload
BodyHTML-safe. - Prefer typed
EmailTemplateDatafor reusable templates. - Add both English and Arabic templates when sending bilingual communication.
- Avoid sending secrets or one-time codes in logs.
SMS
Flow
SmsChannelvalidates the payload type.- Creates one request and one delivery.
- Normalizes
PhoneNumberwithRegionCode. - Resolves SMS config.
- Sends through
GenericHttpSmsProvider.
Provider Contract
The current provider posts JSON to the configured SMS BaseUrl:
json
{
"recipients": "+201000000000",
"body": "Message text",
"sender": "Microtec"
}It sends:
text
Authorization: Bearer <api-token>Best Practices
- Always pass a correct ISO-style region code such as
EG. - Keep SMS content concise.
- Store sender identity in channel config unless a specific send needs an override.
- Add provider response parsing before building business logic around SMS-specific provider states.
Push
Flow
PushChannelvalidates the payload type.- Requires
UserIds. - Creates one
NotificationRequestper user. PushMessagingServiceresolves matching active and valid device tokens.- Resolves FCM provider by
ApplicationTargetandPreferredProvider. - Sends multicast through FCM.
- Creates one delivery per device token.
- Invalid token responses mark device registrations invalid.
Device Resolution
Device tokens are filtered by:
UserIdIsActiveIsTokenValidPlatformApplicationTarget
Registering Tokens
Use IDeviceTokenClient or the proxy route.
csharp
await deviceTokenClient.RegisterAsync(new RegisterDeviceTokenRequest
{
Token = "<device-token>",
Platform = PlatformType.Mobile,
ApplicationTarget = ApplicationTarget.ERP,
Provider = PushProviders.FCM,
DeviceModel = "Android"
}, cancellationToken);For the same user, subdomain, platform, and application target, registering again updates the existing active token row.
Best Practices
- Register tokens when the app starts and when the push provider refreshes the token.
- Send to user ids, not raw device tokens, from business services.
- Set
ApplicationTargetaccurately so ERP, POS, and Admin Portal credentials remain isolated. - Use
RouteUrlfor client navigation. - Treat push as eventually consistent: devices may be offline, expired, or revoked.
WhatsApp
Send Flow
WhatsAppChannelresolves WhatsApp config.- Creates one request and one delivery.
- Reads template name from
Data["__wa_template_name"]. - Finds a local
WhatsAppTemplatefor the current subdomain. - Requires
T2TemplateIdandSyncStatus = Approved. - Builds the T2 template text with ordered parameters.
- Sends through Msegat/T2.
- Schedules status checking when T2 returns a provider message id.
Template Metadata
Prefer the builder:
csharp
var payload = NotificationBuilder.WhatsApp()
.WithSubdomain("acme")
.To("+201000000000")
.WithTemplate(WhatsAppTemplateNames.SalesInvoiceEn)
.WithTemplateParams(["Customer", "INV-1001"])
.WithTemplateDocument("https://files.example/invoice.pdf", "invoice.pdf")
.Build();Provisioning
WhatsApp provisioning:
- validates Msegat credentials
- ensures mandatory local templates exist
- syncs them to T2
- waits for approval
- schedules approval checks until complete or timed out
Statuses:
NotStartedQueuedRunningWaitingForApprovalCompletedFailed
Best Practices
- Run provisioning after creating or changing Msegat WhatsApp credentials.
- Do not send WhatsApp templates until provisioning status is
Completed. - Keep template parameter order stable because T2 parameters are positional.
- Store entity metadata for traceability when WhatsApp is related to invoices or other business documents.
Notification Center
Notification Center uses persisted request metadata to show notifications to users and admins.
User operations:
- list all notifications
- list by channel
- get unread count
- mark one or many as read
- delete one notification
Admin operations:
- list all notifications with filters
- view channel-specific details
- retry failed notifications
Best Practices
- Populate
ModuleName,ModuleNameAr,ServiceName,ServiceNameAr, andNotificationSettingType. - For push, set
RouteUrlso frontends can navigate from the notification. - Do not rely on raw provider payloads for UI display. Use metadata and response DTOs.