Skip to content

ASP.NET Core

Guide for applications built with ASP.NET Core 8+ (.NET). Mailexam connects as SMTP via the MailKit library.

What you need

Copy from the welcome email (or dashboard) for your project:

  • YOUR_LOGIN — SMTP login (for example, xxxxx);
  • YOUR_PASSWORD — SMTP password (a unique pair with the login);
  • host — YOUR_LOGIN.mailexam.io (matches the login).

1. Dependencies

dotnet new web -n MailexamWeb
cd MailexamWeb
dotnet add package MailKit

Fragment of MailexamWeb.csproj:

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="MailKit" Version="4.8.0" />
  </ItemGroup>
</Project>

2. Environment variables

Set variables before launch (User Secrets, IDE Run Configuration, or .env via your tool):

MAILEXAM_LOGIN=YOUR_LOGIN
MAILEXAM_PASSWORD=YOUR_PASSWORD
MAILEXAM_PORT=587
MAIL_FROM=noreply@example.test

SMTP host: YOUR_LOGIN.mailexam.io.

Sender address

MAIL_FROM can be any test address — the message goes to Mailexam, not to a real recipient.

Alternative ports

MAILEXAM_PORT=587

SecureSocketOptions.StartTls

MAILEXAM_PORT=2525

STARTTLS, same as for 587.

MAILEXAM_PORT=465

SecureSocketOptions.SslOnConnect

MAILEXAM_PORT=25

SecureSocketOptions.None

3. Sending service

Services/MailService.cs:

using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;

namespace MailexamWeb.Services;

public class MailService
{
    public async Task SendTestAsync(string? to, string? subject, string? body, CancellationToken ct = default)
    {
        var login = Environment.GetEnvironmentVariable("MAILEXAM_LOGIN")
            ?? throw new InvalidOperationException("MAILEXAM_LOGIN is not set");
        var password = Environment.GetEnvironmentVariable("MAILEXAM_PASSWORD")
            ?? throw new InvalidOperationException("MAILEXAM_PASSWORD is not set");

        var port = int.Parse(Environment.GetEnvironmentVariable("MAILEXAM_PORT") ?? "587");
        var from = Environment.GetEnvironmentVariable("MAIL_FROM") ?? "noreply@example.test";

        to ??= "user@example.test";
        subject ??= "ASP.NET Core + Mailexam";
        body ??= "Mailexam test from ASP.NET Core";

        var message = new MimeMessage();
        message.From.Add(MailboxAddress.Parse(from));
        message.To.Add(MailboxAddress.Parse(to));
        message.Subject = subject;
        message.Body = new TextPart("plain") { Text = body };

        using var client = new SmtpClient();
        await client.ConnectAsync($"{login}.mailexam.io", port, GetSecureSocketOptions(port), ct);
        await client.AuthenticateAsync(login, password, ct);
        await client.SendAsync(message, ct);
        await client.DisconnectAsync(true, ct);
    }

    private static SecureSocketOptions GetSecureSocketOptions(int port) => port switch
    {
        465 => SecureSocketOptions.SslOnConnect,
        25 => SecureSocketOptions.None,
        _ => SecureSocketOptions.StartTls,
    };
}

4. Minimal API

Program.cs:

using MailexamWeb.Services;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<MailService>();

var app = builder.Build();

app.MapPost("/mail/test", async (SendRequest request, MailService mail, CancellationToken ct) =>
{
    await mail.SendTestAsync(request.To, request.Subject, request.Body, ct);
    return Results.Ok(new { status = "ok" });
});

app.Run("http://127.0.0.1:8080");

public record SendRequest(string? To, string? Subject, string? Body);

Start and verify:

export MAILEXAM_LOGIN=YOUR_LOGIN
export MAILEXAM_PASSWORD=YOUR_PASSWORD
export MAILEXAM_PORT=587
export MAIL_FROM=noreply@example.test

dotnet run
curl -X POST http://127.0.0.1:8080/mail/test \
  -H 'Content-Type: application/json' \
  -d '{"to":"user@example.test","subject":"Test","body":"Hello"}'

The message will appear in the Mailexam dashboard → your project → inbox.

User Secrets (local)

dotnet user-secrets init
dotnet user-secrets set MAILEXAM_LOGIN YOUR_LOGIN
dotnet user-secrets set MAILEXAM_PASSWORD YOUR_PASSWORD

To read secrets as environment variables in dev you can add the Microsoft.Extensions.Configuration.UserSecrets package — in the example above export or CI secrets are sufficient.

5. Local development and CI

Environment Recommendation
local User Secrets or variables in Run Configuration
CI secrets MAILEXAM_LOGIN, MAILEXAM_PASSWORD in GitLab CI/CD Variables

Example for .gitlab-ci.yml:

variables:
  MAILEXAM_LOGIN: $MAILEXAM_LOGIN
  MAILEXAM_PASSWORD: $MAILEXAM_PASSWORD
  MAILEXAM_PORT: "587"
  MAIL_FROM: "noreply@example.test"

After an integration test, verify delivery via the Mailexam API.

6. Common issues

TLS or authentication failed error

  • Connection host — {login}.mailexam.io, login in AuthenticateAsync — from the email.
  • Login and password are a pair from the email for one project.

Port 587

  • Use SecureSocketOptions.StartTls, not SslOnConnect.

Message not in the dashboard

  • View the inbox of the same Mailexam project.
  • Enable verbose logs: "Logging:LogLevel:Default": "Debug" in appsettings.Development.json.

See also