Connect24.Sdk
0.6.0
dotnet add package Connect24.Sdk --version 0.6.0
NuGet\Install-Package Connect24.Sdk -Version 0.6.0
<PackageReference Include="Connect24.Sdk" Version="0.6.0" />
<PackageVersion Include="Connect24.Sdk" Version="0.6.0" />
<PackageReference Include="Connect24.Sdk" />
paket add Connect24.Sdk --version 0.6.0
#r "nuget: Connect24.Sdk, 0.6.0"
#:package Connect24.Sdk@0.6.0
#addin nuget:?package=Connect24.Sdk&version=0.6.0
#tool nuget:?package=Connect24.Sdk&version=0.6.0
Connect24 .NET SDK
One API for email, SMS and WhatsApp.
dotnet add package Connect24.Sdk
Quick start
Get your account id and an API key from the Connect24 dashboard (Settings → API keys).
using Connect24;
var client = new Connect24Client(
accountId: "acc_3f9c1a7b4e2d",
apiKey: Environment.GetEnvironmentVariable("CONNECT24_API_KEY")!);
await client.Messages.SendSmsAsync(
to: "+27821234567",
text: "Your payment is due tomorrow.");
Every channel, one shape
// SMS
await client.Messages.SendSmsAsync("+27821234567", "Your delivery is on its way.");
// WhatsApp — free-form inside the 24-hour window, a template outside it
await client.Messages.SendWhatsAppAsync("+27821234567", "Your order has shipped.");
await client.Messages.SendWhatsAppAsync("+27821234567", templateName: "payment_reminder");
// Email
await client.Messages.SendEmailAsync(
to: "customer@example.com",
subject: "Payment reminder",
html: "<p>Your account is overdue.</p>",
from: new MessageSender("collections@acme.co.za", "Acme Collections"));
Attachments
await client.Messages.SendEmailAsync(
to: "customer@example.com",
subject: "Your invoice",
html: "<p>Invoice attached.</p>",
attachments: [new Attachment(
name: "invoice.pdf",
contentType: "application/pdf",
content: Convert.ToBase64String(File.ReadAllBytes("invoice.pdf")))]);
For an inline image, give the attachment a contentId and reference it as <img src="cid:logo">.
Total attachment size is capped at roughly 7 MB per message.
Templates
Store the copy once, send it with values:
await client.Templates.CreateAsync(new TemplateRequest(
name: "payment_reminder",
subject: "Payment due, {{name}}",
html: "<p>Hi {{name}}, {{amount}} is due on {{date}}.</p>"));
await client.Messages.SendTemplateAsync(
MessageChannel.Email, "customer@example.com", "payment_reminder",
new Dictionary<string, string> { ["name"] = "Thabo", ["amount"] = "R450", ["date"] = "25 Aug" });
Editing a template bumps its version, so a send stays traceable to the body that produced it.
Not sending twice
Pass an idempotency key when a network failure leaves you unsure whether a send arrived. A repeat with the same key returns the original message instead of sending again:
await client.Messages.SendAsync(request, idempotencyKey: $"invoice-{invoiceId}");
Suppressions
Hard bounces, spam complaints and unsubscribes are suppressed automatically, and sending to a suppressed address returns 403 rather than silently dropping the message — so your code can tell "sent" from "refused".
var blocked = await client.Suppressions.ListAsync();
await client.Suppressions.AddAsync("someone@example.com", reason: "unsubscribe");
await client.Suppressions.RemoveAsync("someone@example.com");
Every email automatically carries the one-click List-Unsubscribe headers mailbox providers expect,
pointing at a hosted unsubscribe page — you do not need to build one.
Checking what happened
var accepted = await client.Messages.SendSmsAsync("+27821234567", "Hello");
var message = await client.Messages.GetAsync(accepted.Id);
Console.WriteLine(message.Status); // queued → sent → delivered
var recent = await client.Messages.ListAsync(channel: MessageChannel.Email, limit: 20);
Dependency injection
builder.Services.AddSingleton(_ => new Connect24Client(
builder.Configuration["Connect24:AccountId"]!,
builder.Configuration["Connect24:ApiKey"]!));
Or supply your own HttpClient (from IHttpClientFactory, with your own retry policy):
var client = new Connect24Client(new Connect24ClientOptions
{
AccountId = "acc_3f9c1a7b4e2d",
ApiKey = apiKey,
HttpClient = httpClientFactory.CreateClient("connect24"),
});
Errors
Failed calls throw Connect24ApiException with the HTTP status:
try
{
await client.Messages.SendSmsAsync("+27821234567", "Hello");
}
catch (Connect24ApiException ex) when (ex.StatusCode == 401)
{
// Key is wrong or revoked.
}
catch (Connect24ApiException ex) when (ex.StatusCode == 400)
{
// ex.Message names the field that was rejected.
}
Sender identity — read this
Until your sending domain is verified, the From line is your account's configured sender, and
the from: you pass becomes the Reply-To:
from: Connect24 <donotreply@<your-account>.azurecomm.net>
reply-to: Acme Collections <collections@acme.co.za> <- what you passed
Replies still reach you, so nothing is lost — but recipients see the platform address, not yours.
Verify a domain in the dashboard to send as collections@acme.co.za with your own display name.
Keeping your key safe
The account id (acc_…) is safe to commit. The API key (ck_live_…) is a secret: load it from
configuration, an environment variable or a secret store. Revoke a leaked key in the dashboard —
revocation takes effect immediately.
Use a ck_test_… key in development: test keys are accepted and recorded, but nothing is
ever sent, delivered or billed. The recipient chooses the
simulated outcome, so you can exercise your failure paths:
| Recipient | Simulated result |
|---|---|
bounced@example.com |
failed, and the address is added to your suppression list |
complained@example.com |
delivered, recorded as a spam complaint, address suppressed |
| anything else | delivered |
Supported platforms
.NET 8 and later, plus .NET Framework 4.6.1+ / .NET Standard 2.0.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.Net.Http (>= 4.3.4)
- System.Text.Json (>= 8.0.5)
-
net8.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.