Solvo Solvo 2.0

Email and SMS

Solvo sends every email and SMS through one pipeline: pick a template → fill it with the platform's or the school's details → save it to the outbox → hand it to the engine you connected. Every message is logged, failures retry on their own, and you can see exactly what was sent.

1. Connect an email engine

Super Admin → Email & SMS engines. Choose an engine, paste the details it asks for, save, then use Send test email. Keys are encrypted before they are stored.

Engine What you need Notes
Resend API key Verify your sending domain at resend.com/domains first.
Mailchimp Transactional (Mandrill) Transactional API key Mailchimp's transactional add-on, not the newsletter API key.
Mailgun Private API key, sending domain, region (US/EU) Use the region your domain was created in.
SendGrid API key with "Mail Send" permission Verify a single sender or domain.
Brevo (Sendinblue) API key (v3)
Postmark Server API token, message stream Stream defaults to outbound.
Amazon SES Access key ID, secret access key, region Uses the SES v2 API with Signature V4. Request production access to leave the sandbox.
ZeptoMail (Zoho) Send-mail token, API host Host is api.zeptomail.com (or .eu, .in …).
Elastic Email API key
MailerSend API token
SMTP Host, port, encryption, username, password Gmail/Workspace needs an app password. cPanel mailboxes work too (port 465 SSL or 587 STARTTLS).
PHP mail() Nothing Uses the server's mail system. Fine for testing, weakest deliverability.
Log only Nothing Renders and logs messages without sending — useful on staging.

Set the From name, From email and Reply-to on the same page. The From address must be on a domain you have verified with the engine.

Deliverability checklist: add the SPF and DKIM records your engine gives you to your domain's DNS, add a DMARC record (v=DMARC1; p=none; rua=mailto:you@yourdomain), and send from an address on that domain. Most "emails go to spam" problems are a missing DKIM record.

2. Connect an SMS gateway

Same page, lower card. Every gateway asks for a default country code (Kenya: 254), used to turn local numbers like 0712 345 678 into +254712345678.

Gateway What you need
Africa's Talking Environment (live/sandbox), username, API key, sender ID or short code
Twilio Account SID, auth token, From number or Messaging Service SID
Advanta SMS (Kenya) API key, partner ID, sender ID
Celcom Africa (Kenya) API key, partner ID, sender ID
Infobip Your base URL (from the Infobip portal), API key, sender
Vonage (Nexmo) API key, API secret, From
Termii API key, sender ID, channel, base URL
Custom HTTP gateway URL, GET or POST, body format (form or JSON), body template with {{to}}, {{message}} and {{sender}} placeholders, extra headers, and the text a successful response contains
Log only Nothing

Then use Send test SMS. SMS templates avoid characters that force Unicode encoding, so a 160-character message costs one credit; the editor shows the character and segment count as you type.

3. Templates

Email & SMS templates lists every template by category, with its audience, channels and whether it has been customised. There are 44 email and 37 SMS templates:

Editing

Open a template to edit the subject, preheader (the grey preview line in the inbox) and body, with a live preview on the right. Click a variable in the list to insert it. Send test sends the current draft to you with sample data. Reset to default removes your changes.

Template language

Syntax Meaning
{{student_name}} Insert a value (HTML-escaped)
{{{message_html}}} Insert a value that is already HTML (used for announcement bodies)
{{#if balance}} … {{/if}} Show the block only when the value is not empty
<a class="btn" href="{{pay_url}}">Pay now</a> A full-width, email-client-safe button in the brand colour
<table class="facts">…</table> A two-column details table (labels left, values right)
<div class="panel">…</div> A tinted call-out box (panel warn amber, panel success green, panel danger red)

Always available: platform_name, brand_name (the school's name on school emails, otherwise the platform's), brand_email, brand_phone, brand_address, brand_website, brand_whatsapp, login_url, year and recipient_name. Each template lists its own extra variables in the editor.

How branding is chosen

4. Per-school sender settings

School Admin → Sender settings: sender name, reply-to address and an email footer note. A school can also connect its own email engine and SMS gateway (handy if it already pays for a bulk SMS sender ID); otherwise it uses the platform's — recommended, nothing to set up.

5. The outbox and message log

Every message lands in the outbox first (comm_outbox). Interactive messages (password resets, receipts) are sent straight away; bulk sends (reminders, invoices) are queued.

scripts/process_outbox.php — run it every 5 minutes from cron — sends queued messages and retries failures after 5 minutes, 30 minutes and 2 hours. Message log shows recipient, template, engine, status and the exact email or SMS as received, with a Retry button for failures.

Statuses: queued, sent, failed (after the last retry), suppressed (the demo edition, which never sends real messages).

6. For developers

// Send a template (school branding when school_id is set, platform branding otherwise)
Comms::email('fee_payment_receipt', $guardian['email'], [
    'recipient_name' => $guardian['full_name'],
    'student_name'   => 'Brian Muthoni',
    'amount'         => 'KES 4,800.00',
], ['school_id' => $schoolId, 'related_type' => 'payment', 'related_id' => $paymentId]);

Comms::sms('fee_payment_receipt', $guardian['phone'], $vars, ['school_id' => $schoolId]);

// Queue instead of sending now (picked up by process_outbox.php)
Comms::email('fee_reminder', $to, $vars, ['school_id' => $schoolId, 'queue' => true]);

New templates go in core/Comms/TemplateLibrary.php (key, name, category, audience, sample variables, email subject/preheader/body and SMS text). New engines implement one method in core/Comms/MailDrivers.php or core/Comms/SmsDrivers.php plus an entry in that file's catalog().