Postal – wysyłka e-mail w ASP.NET MVC

Wysyłka e-mail w ASP.NET MVC

Wcześniej czy później w aplikacji następuje potrzeba wysłania wiadomości e-mail do użytkownika. W aplikacji ASP.NET MVC można zrobić to na wiele sposób. Możemy ręcznie przygotować treść wiadomości oraz wysłać ją z wykorzystaniem klasy SmtpClient. Możemy też skorzystać z tego, co daje ASP.NET MVC, i użyć widoku do generowania treści wiadomości. W tym wpisie pokażę, jak wykorzystać bibliotekę Postal do wysyłki e-mail w ASP.NET MVC.

Postal – przygotowanie wiadomości

Biblioteka Postal (a dokładnie Postal.MVC5 dla piątej wersji frameworka) bazuje na silniku ASP.NET MVC do generowania treści wiadomości e-mail. Możemy korzystać z silnie typowanych widoków, jak podczas codziennej pracy. Jest kilka drobnych różnic w stosunku do używania normalnych widoków.

W pierwszej kolejności model przekazywany do widoku musi dziedziczyć po klasie Email. Oczywiście możemy do niego dodać własne właściwości, na podstawie których później przygotujemy w widoku treść wiadomości. Najlepiej zobaczyć to na przykładzie wiadomości wysyłanej do użytkownika po założeniu konta:

public class RegisterEmail : Email
{
public string FirstName { get; set; }
public string Email { get; set; }
}

W przykładzie do widoku przekazuję imię użytkownika oraz jego adres e-mail. Sam widok różni się od zwykłego widoku informacjami o wysyłce e-mail na początku:

@model PostalExample.ViewModels.Users.RegisterEmail
To: @Model.Email
Subject: Nowe konto
<h1>Witaj @Model.FirstName!</h1>
<p>Dziękujemy za założenie konta.</p>

Na początku widoku określamy ustawienia do wysyłki wiadomości, czyli między innymi:

  • To – email użytkownika
  • Subject – tytuł wiadomości
  • inne ustawienia, takie jak kopia, ukryta kopia itp. opisane w dokumentacji.

Domyślnie widok powinien znajdować się w katalogu ~/Views/Emails lub ~/Views/Shared. Można to zmienić na przykład w konstruktorze klasy dziedziczącej po Email.

Darmowy kurs Visual Studio

Pracując z setkami programistów, zauważyłem, że większość osób nie pracuje efektywnie w Visual Studio. W skrajnych przypadkach korzystali z kopiowania z wykorzystaniem menu Edit. Wiem, że to dziwne, ale naprawdę niektórzy tak pracują. Dlatego postanowiłem stworzyć kurs Visual Studio – aby pomóc koleżankom i kolegom w efektywniejszej pracy.

Przygotowałem 30 lekcji e-mail, w których pokażę Ci, w jaki sposób pracować efektywniej i szybciej w Visual Studio. Poznasz dodatki, bez których nie wyobrażam sobie pracy w tym IDE.

Po więcej informacji zapraszam na dedykowaną stronę kursu: Darmowy Kurs Visual Studio.

Quiz C#

Ostatnio przygotowałem również quiz C#, w którym możesz sprawdzić swoją wiedzę. Podejmiesz wyzwanie?

Postal – wysyłka wiadomości

Wysyłka wiadomości z wykorzystaniem Postal również jest bardzo prosta. Wystarczy utworzyć instancję wcześniej utworzonej klasy dziedziczącej po Email (w przykładzie to RegisterEmail) i wywołać metodę Send z tej klasy. W swoich aplikacjach logikę tę zamykam w dedykowanych klasach, aby można było to później dużo łatwiej testować za pomocą testów jednostkowych.

W przykładzie utworzyłem klasę UsersMailer, która zawiera metody związane z wysyłką wiadomości e-mail dla użytkowników:

public class UsersMailer : IUserMailer
{
public void SendRegisterEmail(User user)
{
var email = new RegisterEmail()
{
Email = user.Email,
FirstName = user.FirstName
};
email.Send();
}
}
public interface IUserMailer
{
void SendRegisterEmail(User user);
}

Do poprawnej wysyłki wiadomości potrzebna jest jeszcze konfiguracja SMTP (poniżej przykład dla Gmaila) w web.config:

<system.net>
<mailSettings>
<smtp from="adres email">
<network enableSsl="true" host="smtp.gmail.com" port="587" userName="nazwa użytkownika" password="hasło" />
</smtp>
</mailSettings>
</system.net>
view raw web.config hosted with ❤ by GitHub

W wyniku działania powyższego kodu otrzymamy takiego email:

testowy email wysłany przez bilbiotekę Postal

HttpContext?

Domyślnie Postal, podobnie jak inne tego typu biblioteki, wymaga, aby wygenerowanie treści wiadomości odbyło się w ramach żądania HTTP. Nam natomiast bardzo często zależy na tym, aby wiadomość była dostarczona. Niestety wcześniej czy później może się okazać, że serwer SMTP nie będzie odpowiadał, przez co wysłanie e-maila w ramach żądania HTTP, w którym przyszły dane, będzie kończyło się wyjątkiem i komunikatem dla użytkownika.

W związku z tym lepiej skorzystać z jakiegoś mechanizmu, który będzie kolejkował wysyłanie wiadomości oraz je ponawiał, gdy zaistnieją jakieś problemy. W kolejnym wpisie pokażę, jak to zrobić z wykorzystaniem biblioteki Hangfire. Problem w tym, że podczas wysyłki wiadomości w tle nie mamy dostępu do kontekstu HTTP, więc biblioteka do wysyłki wiadomości musi umożliwić działanie bez kontekstu. Na szczęście biblioteka Postal daje taką możliwość.

Aby wysyłać wiadomość bez kontekstu HTTP, należy nieco zmienić metodę wysyłającą wiadomość. W swoim kodzie dodaję bazową klasę BaseMailer, która jest klasą bazową dla wszystkich klas wysyłających e-maile. BaseMailer zawiera metodę Send, która nie wymaga kontekstu HTTP. BaseMailer wygląda następująco:

public class BaseMailer
{
protected void Send(Email email)
{
var mailerName = GetType().Name.Replace("Mailer", string.Empty);
var viewsPath = Path.GetFullPath(string.Format(HostingEnvironment.MapPath(@"~/Views/Emails/{0}"), mailerName));
var engines = new ViewEngineCollection();
engines.Add(new FileSystemRazorViewEngine(viewsPath));
var emailService = new EmailService(engines);
emailService.Send(email);
}
}
view raw BaseMailer.cs hosted with ❤ by GitHub

Jak widać, musimy do klasy EmailService z biblioteki Postal przekazać ręcznie informacje o silnikach generujących widoki. Dodatkowo zmieniam też domyślną lokalizację plików widoków dla wiadomości. Te widoki, podobnie jak normalne, grupuję w dedykowane foldery dla każdej klasy Mailer, co pozwala utrzymać lepszy porządek, gdy w aplikacji wysyłamy wiele różnych wiadomości e-mail. W przykładzie lokalizacja pliku widoku zmieni się z ~/Views/Emails/Register.cshtml na ~/Views/Emails/Users/Register.cshtml.

Sama klasa UsersMailer docelowo wygląda zaś tak:

public class UsersMailer : BaseMailer, IUserMailer
{
public void SendRegisterEmail(User user)
{
var email = new RegisterEmail()
{
Email = user.Email,
FirstName = user.FirstName
};
Send(email);
}
}

Zmieniły się dwie rzeczy:

  • UsersMailer dziedziczy po BaseMailer (linijka 1)
  • Zamiast metody Send z RegisterEmail wywołujemy metodę Send z klasy bazowej i przekazujemy obiekt RegisterEmail jako parametr (linijka 11).

Podsumowanie

Dzięki bibliotece Postal możemy w łatwy sposób wysyłać e-mail w ASP.NET MVC, pisząc właściwie ten sam kod, jaki tworzymy podczas pracy z normalnymi widokami. Dodatkowo Postal wspiera wysyłanie wiadomości bez żądania HTTP, dzięki czemu możemy ją wykorzystać do wysyłania wiadomości przy użyciu kolejek, aby zapewnić większą niezawodność aplikacji. O tym będzie mowa w kolejnym wpisie na blogu.

Zachęcam do pobrania przykładu z githuba i przetestowania biblioteki w praktyce. Po pobraniu przykładu należy dodać w web.config informację o serwerze SMTP.

A Ty w jaki sposób wysyłasz wiadomości e-mail w swoich aplikacjach?

1 thought on “Postal – wysyłka e-mail w ASP.NET MVC

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.