< Summary - MechanicsSoftware — Coverage Report

Information
Class: MechanicsSoftware.Infrastructure.Notifications.SmtpEmailNotifier
Assembly: MechanicsSoftware.Infrastructure
File(s): /home/runner/work/mechanics-software/mechanics-software/src/MechanicsSoftware.Infrastructure/Notifications/SmtpEmailNotifier.cs
Line coverage
100%
Covered lines: 21
Uncovered lines: 0
Coverable lines: 21
Total lines: 117
Line coverage: 100%
Branch coverage
100%
Covered branches: 12
Total branches: 12
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%1212100%

File(s)

/home/runner/work/mechanics-software/mechanics-software/src/MechanicsSoftware.Infrastructure/Notifications/SmtpEmailNotifier.cs

#LineLine coverage
 1using System.Diagnostics.CodeAnalysis;
 2using System.Net;
 3using System.Net.Mail;
 4using Microsoft.Extensions.Configuration;
 5using MechanicsSoftware.Application.Abstractions;
 6using MechanicsSoftware.Domain.ValueObjects;
 7
 8namespace MechanicsSoftware.Infrastructure.Notifications;
 9
 10public sealed class SmtpEmailNotifier : IEmailNotifier
 11{
 12    private readonly string _host;
 13    private readonly int _port;
 14    private readonly string _user;
 15    private readonly string _pass;
 16    private readonly string _from;
 17
 2218    public SmtpEmailNotifier(IConfiguration configuration)
 2219    {
 2220        _host = configuration["SMTP_HOST"]
 2221            ?? throw new InvalidOperationException(
 2222                "SMTP host not configured. Set the 'SMTP_HOST' environment variable.");
 23
 2024        var portRaw = configuration["SMTP_PORT"]
 2025            ?? throw new InvalidOperationException(
 2026                "SMTP port not configured. Set the 'SMTP_PORT' environment variable.");
 27
 1828        if (!int.TryParse(portRaw, out _port))
 1029            throw new InvalidOperationException(
 1030                $"Invalid value for 'SMTP_PORT': '{portRaw}'. Expected a numeric port (e.g. 587).");
 31
 832        _user = configuration["SMTP_USER"]
 833            ?? throw new InvalidOperationException(
 834                "SMTP user not configured. Set the 'SMTP_USER' environment variable.");
 35
 636        _pass = configuration["SMTP_PASS"]
 637            ?? throw new InvalidOperationException(
 638                "SMTP password not configured. Set the 'SMTP_PASS' environment variable.");
 39
 440        _from = configuration["SMTP_FROM"]
 441            ?? throw new InvalidOperationException(
 442                "SMTP sender address not configured. Set the 'SMTP_FROM' environment variable.");
 243    }
 44
 45    [ExcludeFromCodeCoverage]
 46    public async Task SendStatusChangedAsync(
 47        string toEmail,
 48        string customerName,
 49        Guid serviceOrderId,
 50        ServiceOrderStatus.Status newStatus,
 51        CancellationToken cancellationToken = default)
 52    {
 53        var subject = $"Atualização da sua Ordem de Serviço #{serviceOrderId}";
 54        var body = BuildBody(customerName, serviceOrderId, newStatus);
 55
 56        using var client = new SmtpClient(_host, _port)
 57        {
 58            Credentials = new NetworkCredential(_user, _pass),
 59            EnableSsl = true
 60        };
 61
 62        using var message = new MailMessage(
 63            from: new MailAddress(_from),
 64            to: new MailAddress(toEmail))
 65        {
 66            Subject = subject,
 67            Body = body,
 68            IsBodyHtml = true
 69        };
 70
 71        await client.SendMailAsync(message, cancellationToken);
 72    }
 73
 74    [ExcludeFromCodeCoverage]
 75    private static string BuildBody(
 76        string customerName,
 77        Guid serviceOrderId,
 78        ServiceOrderStatus.Status newStatus)
 79    {
 80        var statusLabel = new ServiceOrderStatus(newStatus).ToString();
 81
 82        return $"""
 83            <!DOCTYPE html>
 84            <html lang="pt-BR">
 85            <head><meta charset="UTF-8" /></head>
 86            <body style="font-family:Arial,sans-serif;background:#f4f4f4;padding:32px;">
 87              <table width="600" cellpadding="0" cellspacing="0"
 88                     style="background:#ffffff;border-radius:8px;padding:32px;margin:auto;">
 89                <tr>
 90                  <td>
 91                    <h2 style="color:#1a1a1a;margin-top:0;">
 92                      Atualização da sua Ordem de Serviço
 93                    </h2>
 94                    <p style="color:#333;">Olá, <strong>{customerName}</strong>!</p>
 95                    <p style="color:#333;">
 96                      Sua Ordem de Serviço <strong>#{serviceOrderId}</strong>
 97                      teve o status atualizado.
 98                    </p>
 99                    <p style="background:#f0f4ff;border-left:4px solid #4f6ef7;
 100                               padding:12px 16px;border-radius:4px;color:#1a1a1a;">
 101                      Novo status: <strong>{statusLabel}</strong>
 102                    </p>
 103                    <p style="color:#555;font-size:14px;">
 104                      Caso tenha dúvidas, entre em contato conosco.
 105                    </p>
 106                    <hr style="border:none;border-top:1px solid #eee;margin:24px 0;" />
 107                    <p style="color:#999;font-size:12px;margin:0;">
 108                      Equipe de Atendimento
 109                    </p>
 110                  </td>
 111                </tr>
 112              </table>
 113            </body>
 114            </html>
 115            """;
 116    }
 117}