Baza danych
Dostawcą usług hostingowych dla mojego bloga jest Webio. Był to mój pierwszy wybór, korzystam od kilku lat. Obecnie moje 3
projekty są opublikowane na ich serwerach. Na początku korzystałem z planu startowego, teraz z uwagi na większą liczbę domen czy baz danych przesiadłem się na jeden z wyższych planów.
Hosting ten jest dla mnie intuicyjny w obsłudze (po zapoznaniu się z kluczowymi możliwościami) - nigdy również nie miałem problemów z obsługą. Jeżeli chcecie zapoznać się z zakresem ich usług zapraszam do skorzystania z linka affiliacyjnego https://www.webio.pl
W tym wpisie nie będziemy zajmować się tworzeniem systemu zarządzania wiadomościami e-mail (mam na myśli regularne powiadomienia o nowych artykułach na blogu). Naszym celem jest dodanie do bloga możliwości zapisania się na Newsletter, weryfikacji adresu odbiory oraz wyświetlenia wiadomości powitalnej.
Teraz już wiecie dlaczego zacząłem zagadnienie od bazy danych. Musimy utworzyć tabelę w której będziemy przechowywać najistotniejsze informacje. Mam tutaj na myśli adres e-mail Czytelnika, klucz weryfikacyjny oraz informację o potwierdzeniu tego adresu. Jeżeli adres nie został potwierdzony nie widzę żadnego sensu wysyłania powiadomień. Co więcej... ktoś mógł podać adres nie należący do danego Czytelnika.
Na potrzeby wpisu utworzyłem prostą tablę:
Implementacja
Czego potrzebujemy po stronie naszej aplikacji? Musimy dokonać połączenia z bazą danych, przygotować widok pozwalający na zapisanie się na newsletter, obsłużyć dane po stronie serwera oraz wysłać stosowne wiadomości e-mail.
Zaczniemy od front-endu. Wydaje mi się, że najlepszym miejscem będzie stopka naszej witryny. Najprostszy kod HTML przedstawia się następująco:
<div class="newsletter">
<p>Newsletter</p>
<p>
Chcesz być na bieżąco z tym co dzieje się na blogu? Zapisz się poniżej:
</p>
<div>
<form method="post" action="@Url.Action("Akcja", "Kontroler")">
<input type="email" id="email" name="email" required />
<input type="submit" value="Zapisz się" />
</form>
</div>
</div>
Na potrzeby bloga dodałem niezbędne style, żeby całość prezentowała się w przyjemny dla oka sposób:
Czytając ten wpis możecie zobaczyć, że w stopce dodałem zakładkę Polityka Prywatności. Wraz z utworzeniem newslettera na swoim blogu musimy powiadomić Czytelników kto jest administratorem danych osobowych, jakie prawa przysługują każdemu, etc. W takim wypadku lepiej być po bezpiecznej stronie...
Obsługa formularza
Jaki jest nasz następny krok? Przygotujemy kontroler, który podany adres e-mail doda do naszej bazy danych wraz z odpowiedniem kodem aktywacji. Kod ten zostanie wysłany na podany adres w celu poprawnej weryfikacji naszego Czytelnika. Zanim jednak do tego przejdziemy przygotujemy prosty szablon wysyłanej wiadomości tak, aby w kolejnym kroku być w pełnej gotowości na implementacje całej akcji.
O co chodzi z szablonami? Możemy przygotować plik HTML, który będzie wysyłany jako nasza wiadomość e-mail. Jest to niezwykle czytelny sposób formatowania wiadomości – nie robimy tego w kodzie. Jedyne na czym tak naprawdę nam zależy to wygenerowanie zwrotnego adresu url z zaszytym kodem. Adres ten wstrzykniemy w nasz szablon po czym wyślemy wiadomość.
W pierwszej kolejności dodamy pusty szablon do naszego projektu:
Na tym etapie przygotujemy prostą wiadomość weryfikacyjną – każdy z Was może ją dopasować do swoich potrzeb zmieniając logo, zmieniając kolorystkę, etc.:
<div class="confirmEmailTemplate" style="max-width:350px;background-color:rgb(240,240,240);margin-left:auto;margin-right:auto;margin-top:20px">
<div class="logo" style="height:auto;border:1px solid rgb(240,240,240)">
<img src="https://www.logaster.com/blog/wp-content/uploads/2018/05/LogoMakr.png" style="width:240px;height:auto;margin-left:auto;margin-right:auto;display:block;margin-top:15px;margin-bottom:15px" />
</div>
<div class="sep" style="height:2px;background-color:white"></div>
<div class="form" style="margin-top:20px;padding-left:5px;padding-right:5px;padding-bottom:5px">
<div class="form-group">
<p>
<span style="font-weight:bold">
Witaj,
</span>
<br />
<span>
Dziękujemy za rejestrację w 'nazwa Twojej firmy'
</span>
</p>
<p>
Aby zakończyć konfigurację konta, potwierdź swój adres e-mail, klikając przycisk poniżej:
</p>
<p style="width:280px;margin-left:auto;margin-right:auto;text-align:center">
<a href="emailCallBackURL" style="width:280px;height:35px;margin-left:auto;margin-right:auto;display:block;padding-bottom:15px;color:white;background-color:rgb(115,221,1);">
<span style="padding-top:16px;display:block">Potwierdź swój adres e-mail</span>
</a>
</p>
<p>
<span style="font-weight:bold">
Dziękujemy,
</span>
<br />
<span>
Zespół 'nazwa Twojej firmy'
</span>
</p>
</div>
</div>
</div>
</div>
Tak przygotowany szablon możemy odpalić w przeglądarce i zobaczyć czy spełnia nasze oczekiwania:
Ja w międzyczasie dopasowałem layout swojej wiadomości
– jesteśmy zatem gotowi na kolejne kroki.
Musimy zapisać dane formularza w bazie danych (wraz z wygenerowanym kodem), przygotować zwrotny link oraz wysłać samą wiadomość. Wszystkim zajmie się przygotowany przez nas kontroler. Spójrzcie na początek implementacji:
using System.Web.Mvc;
using MyPersonalWebsite.Models;
namespace MyPersonalWebsite.Controllers
{
public class NewsletterController : Controller
{
// POST: Newsletter/Subscribe
// Wysyłanie wiadomości e-mail
[HttpPost]
[AllowAnonymous]
public async Task<ActionResult> Subscribe(string email)
{
try
{
return RedirectToAction("...");
}
catch
{
return View();
}
}
// GET: Newsletter/ConfirmSubscription
// Potwierdzenie zapisania się na newsletter
[AllowAnonymous]
[HttpGet]
public ActionResult ConfirmSubscription(string email, Guid code)
{
try
{
return RedirectToAction("...");
}
catch
{
return View();
}
}
// GET: Newsletter/Unsubscribe
// Wypisanie się z listy
[HttpGet]
[AllowAnonymous]
public ActionResult Unsubscribe(string email, Guid code)
{
try
{
return RedirectToAction("...");
}
catch
{
return View();
}
}
// GET: Newsletter/Unsubscribe
// A tutaj dodatkowa metoda pozwalająca zebrać feedback od Czytelników
// Możesz poprosić o powód rezygnacji z subskrypcji newslettera
[HttpPost]
[AllowAnonymous]
public ActionResult Unsubscribe(string message)
{
try
{
return RedirectToAction("...");
}
catch
{
return View();
}
}
}
}
Jak widzicie przygotowałem prosty kontroler wraz z czterama możliwymi akcjami, tj. subskrypcja, potwierdzenie, wypisanie się z listy oraz prośba o powód wypisania się z newslettera. Dodatkowo, wykorzystując Entity Framework skonfigurowałem połączenie z bazą danych. Etap ten pomijam ponieważ pisałem artykuły dotyczące tego procesu zarówno dla ASP.NET MVC oraz ASP.NET Core.
Dodajmy zatem do tabeli bazy danych niezbędne dane:
using (PersonalWebsiteEntities db = new PersonalWebsiteEntities())
{
Newsletter newsletterData = new Newsletter();
newsletterData.Email = email;
newsletterData.VerificationCode = verificationCode;
newsletterData.IsVerified = false;
db.Newsletter.Add(newsletterData);
db.SaveChanges();
}
Połowa drogi za nami, musimy jeszcze wysłać e-mail
do naszego Czytelnika. W tym celu wykorzystamy klasę IdentityConfig.cs gdzie dokonamy własnej implementacji i konfiguracji mechanizmu wysyłania wiadomości – stawiamy na czytelność i wielokrotne użycie kodu w różnych wariantach:
public Task SendAsync(string userEmail, string subject, string body)
{
MailMessage mail = new MailMessage();
mail.To.Add(userEmail);
mail.From = new MailAddress("adres z którego wysyłamy wiadomość korzystając z usług dostawcy");
mail.Subject = subject;
// Formatowanie wiadomości
StringBuilder sb = new StringBuilder();
sb.AppendLine();
sb.AppendLine(body);
mail.Body = sb.ToString();
mail.IsBodyHtml = true;
SmtpClient smtp = new SmtpClient();
smtp.Host = "smtp.webio.pl";
smtp.Port = 587;
smtp.UseDefaultCredentials = false;
smtp.Credentials = new System.Net.NetworkCredential("dane_uzytkownika", "haslo");
smtp.EnableSsl = true;
smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
return smtp.SendMailAsync(mail);
}
Pamiętajcie o odpowiedniej konfiguracji swojego konta pocztowego.
Baza danych przygotowana, szablon wiadomości sprawdzony, serwis pozwalający na wysłanie również – pora złożyć wszystko w logiczną całość:
// POST: Newsletter/Subscribe
// Wysyłanie wiadomości e-mail
[HttpPost]
[AllowAnonymous]
public async Task<ActionResult> Subscribe(string email)
{
try
{
// kod weryfikacyjny
Guid verificationCode = Guid.NewGuid();
// dodajemy wymagane dane do odpowiedniej tabeli
using (PersonalWebsiteEntities db = new PersonalWebsiteEntities())
{
Newsletter newsletterData = new Newsletter();
newsletterData.Email = email;
newsletterData.VerificationCode = verificationCode;
newsletterData.IsVerified = false;
db.Newsletter.Add(newsletterData);
db.SaveChanges();
}
// Serwis pozwalający na wysyłanie wiadomości e-mail
EmailService emailService = new EmailService();
// Zwrotny adres url niezbędny do potwierdzenia subskrypcji
var callbackUrl = Url.Action("ConfirmSubscription", "Newsletter", new { email = email, code = verificationCode }, protocol: Request.Url.Scheme);
// Zwrotny adres url niezbędny do wypisania się z newslettera
var emailCallBackUnsubscribeUrl = Url.Action("Unsubscribe", "Newsletter", new { email = email, code = verificationCode }, protocol: Request.Url.Scheme);
// Wiadomość wygenerowana na bazie szablonu z załączonym adresem zwrotnym
string htmlMessage = this.FormatVerificationMessage(callbackUrl, emailCallBackUnsubscribeUrl);
await emailService.SendAsync(email, "Newsletter: potwierdź swój adres e-mail!", htmlMessage);
// Widok potwierdzający wysłanie wiadomości i prośba o weryfikację
return View();
}
catch (Exception ex)
{
// Widok informujący o błędzie...
return RedirectToAction("Index", "Error", new { message = ex.Message, innerException = ex.InnerException.Message });
}
}
#region Useful methods
/// <summary>
/// Formatowanie wiadomości na bazie dostarczonego szablonu oraz zwrotnego adresu url
/// </summary>
/// <param name="callBackUrl"></param>
/// <returns></returns>
public string FormatVerificationMessage(string callBackUrl, string emailCallBackUnsubscribeUrl)
{
string htmlMessage = String.Empty;
string filePath = String.Empty;
filePath = HttpContext.Server.MapPath("~/Content/Templates/ConfirmEmailTemplate.html");
htmlMessage = System.IO.File.ReadAllText(filePath);
htmlMessage = htmlMessage.Replace("emailCallBackURL", callBackUrl);
htmlMessage = htmlMessage.Replace("emailCallBackUnsubscribeUrl", emailCallBackUnsubscribeUrl);
return htmlMessage;
}
#endregion
Jeżeli wszystko przebiegło pomyślnie wiadomość powinna zostać wysłana przez dostawcę Waszych usług. W ramach testów zapraszam Was do skorzystania z mojego newslettera: