← Back to all posts
2026-10-04 · MailAnvil Team

Kirim Email Transaksional dengan ASP.NET Core dan MailAnvil (C#)

Backend fintech dan enterprise Indonesia masih banyak pakai .NET. Sayangnya provider email API populer seperti SendGrid atau Mailgun butuh kartu kredit untuk top-up — hambatan nyata buat developer lokal. Tutorial ini menunjukkan cara integrasi MailAnvil ke aplikasi ASP.NET Core, dengan QRIS/GoPay sebagai metode bayar dan harga IDR 2,4x lebih murah di volume 50 ribu email/bulan.

Kenapa MailAnvil untuk ASP.NET Core?

Fitur MailAnvil SendGrid Mailgun
Harga 10K/bulan Rp 149rb $20 (~Rp 320rb) $35 (~Rp 560rb)
Bayar pakai QRIS, GoPay Kartu kredit Kartu kredit
Latency dari Jakarta ~10ms (CF edge) ~180ms (US relay) ~200ms (US relay)
MCP server Native Community Community
Docs Bahasa Ya Tidak Tidak

Setup Project

dotnet new webapi -n MailAnvilEmailApp
cd MailAnvilEmailApp

HttpClient sudah bawaan .NET — tidak perlu library tambahan.

Simpan API key di appsettings.json (atau environment variable untuk production):

{
  "MailAnvil": {
    "ApiKey": "re_xxxxxxxxxxxxxxxx"
  }
}

Service Class

Buat file Services/MailAnvilService.cs:

using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;

public class MailAnvilService
{
    private readonly HttpClient _http;
    private readonly string _apiKey;

    public MailAnvilService(HttpClient http, IConfiguration config)
    {
        _http = http;
        _apiKey = config["MailAnvil:ApiKey"]
            ?? throw new InvalidOperationException("MAILANVIL_API_KEY tidak diset");
        _http.BaseAddress = new Uri("https://api.mailanvil.com/v1/");
        _http.DefaultRequestHeaders.Authorization =
            new AuthenticationHeaderValue("Bearer", _apiKey);
    }

    public async Task<JsonElement> SendEmailAsync(string to, string subject, string html)
    {
        var payload = JsonSerializer.Serialize(new
        {
            from = "[email protected]",
            to,
            subject,
            html
        });

        using var content = new StringContent(payload, Encoding.UTF8, "application/json");
        var response = await _http.PostAsync("send", content);
        var body = await response.Content.ReadAsStringAsync();

        if (!response.IsSuccessStatusCode)
            throw new HttpRequestException(
                $"MailAnvil send gagal: {(int)response.StatusCode} {body}");

        return JsonSerializer.Deserialize<JsonElement>(body);
    }
}

Registrasi DI

Di Program.cs:

builder.Services.AddHttpClient<MailAnvilService>();
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();

AddHttpClient memakai IHttpClientFactory — koneksi reuse, tidak ada socket exhaustion.

Contoh: Kirim OTP

Buat Controllers/OtpController.cs:

using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/otp")]
public class OtpController : ControllerBase
{
    private readonly MailAnvilService _mail;

    public OtpController(MailAnvilService mail) => _mail = mail;

    [HttpPost("kirim")]
    public async Task<IActionResult> KirimOtp([FromBody] KirimOtpRequest req)
    {
        var kode = Random.Shared.Next(100000, 999999).ToString();

        var html = $@"
<div style=""font-family: Arial, sans-serif; max-width: 400px; margin: 0 auto;"">
  <h2>Kode Verifikasi Anda</h2>
  <p>Kode OTP Anda: <strong style=""font-size: 24px; color: #ff801f;"">{kode}</strong></p>
  <p>Kode ini berlaku selama 5 menit. Jangan bagikan kode ini kepada siapa pun.</p>
</div>";

        await _mail.SendEmailAsync(req.Email, "Kode Verifikasi Anda", html);
        return Ok(new { terkirim = true });
    }
}

public record KirimOtpRequest(string Email);

Simpan kode OTP di Redis/cache dengan TTL 5 menit, bandingkan saat user submit. Jangan kirim ulang lebih dari 3x per jam — throttle rate limit di level aplikasi.

Penanganan Error

Dua kelas error yang perlu dibedakan:

  1. 4xx — payload salah atau API key invalid. Jangan retry; perbaiki request.
  2. 5xx / timeout — upstream sementara. Retry dengan exponential backoff maksimal 3x.
for (int attempt = 1; attempt <= 3; attempt++)
{
    try
    {
        await _mail.SendEmailAsync(to, subject, html);
        break;
    }
    catch (HttpRequestException) when (attempt < 3)
    {
        await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt)));
    }
}

Verifikasi Domain

Sebelum production, verifikasi domain pengirim di dashboard MailAnvil (app.mailanvil.com):

  1. Tambahkan domain → MailAnvil generate record DNS SPF, DKIM, DMARC.
  2. Pakai Cloudflare DNS? DKIM di-setup otomatis — tidak perlu copy-paste record manual.
  3. Tunggu verifikasi (biasanya < 5 menit).

Domain belum verifikasi = email masuk spam atau ditolak. Jangan skip langkah ini.

Langkah Berikutnya