Pro odesílání emailové zprávy v .NETu slouží namespace System.Net.Mail a resp. hlavně jeho třídy MailMessage a SmtpClient. Obecný postup je, že pomoci třídy MailMessage nejprve vytvoříme vlastní zprávu a tu následně odešleme pomoci třídy SmtpClient.
Pro odeslání musíme znát adresu SMTP serveru, přes který chceme zprávu odeslat, a musíme mít na něj přístup a nastavená práva. Konfiguraci SMTP klienta lze buď programově nastavit na instanci třídy SmtpClient pomoci vlastností (nejdůležitější jsou Host, Port, Credentials a UseDefaultCredentials) nebo třída použije konfiguraci ze sekce <system.Net>/<mailSettings> konfiguračního app.config nebo web.config souboru.
V konfiguraci lze také SMTP klienta přepnout na pickup directory, což znamená, že se emaily nebudou přímo odesílat, ale jen se uloží do určené složky jako soubory. Z této složky může emaily odesílat jiný proces nebo lze pickup directory využít např. pro testování, takže se na testovací instanci aplikace nemusíme bát, že se budou rozesílat maily ostrým zákazníkům.
Konfigurace <mailSettings> může vypadat například takto:
<system.net>
<mailSettings>
<smtp deliveryMethod="Network" from="[email protected]">
<network host="mail.domena.cz" port="25" userName="user" password="password" defaultCredentials="false" />
</smtp>
</mailSettings>
</system.net>
Toto API je naprosto obecné a umožňuje odeslat jak textové tak i HTML maily, maily obsahující přílohy (Attachments), zprávu, která je najednou ve více formátech (AlternateViews), i například HTML zprávu obsahující vložené obrázky (LinkedResources).
Velmi často ale potřebujeme odesílat automaticky generované emaily na základě připravené šablony, do které se konkrétní data doplní pouze na určená místa v šabloně (tzv. replacements). Šablonu můžeme mít přitom například buď přímo zabuildovanou v aplikaci jako resource nebo v externím souboru.
Protože je tento typ scénáře dost častý a API třídy MailTemplate je pro něho moc obecné, používám vlastní třídu MailDefinition, která třídu MailMessage pouze interně využívá a dále řeší:
- Načtení obsahu textové nebo HTML šablony pro emailovou zprávu z externího souboru (vlastnost BodyFileName). Jinak lze obsah šablony předat i přímo v parametru body při volání jednotlivých metod třídy.
- Načtení subjectu emailové zprávy přímo z elementu <title> HTML šablony (v případě, kdy je výhodné, aby být subject přímo součástí šablony).
- Doplnění předaných replacements dat jak v těle tak i v subjektu zprávy.
- Doplnění adresy odesílatele nebo adres příjemců na určená místa v těle nebo subjektu zprávy (například na místo označené jako <%From%>).
- Třída podporuje přílohy (Attachments) i obrázky vložené do HTML šablony (EmbeddedObjects).
Třída obsahuje metodu CreateMailMessage, která vrací vytvořený objekt MailMessage, a metodu Send pro přímé odeslání zprávy s využitím výchozího nastavení třídy SmtpClient (tj. konfigurace v .config souboru).
Tímto dávám třídu MailDefinition veřejně k dispozici. Její implementace je následující:
using System;
using System.IO;
using System.Linq;
using System.Net.Mail;
using System.Net.Configuration;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace IMP.Shared
{
internal class MailDefinition
{
#region member types definition
private enum EmailReplacementType
{
From,
To,
CC,
Bcc
}
#endregion
#region member varible and default property initialization
public string BodyFileName { get; set; }
public string From { get; set; }
public string CC { get; set; }
public string Bcc { get; set; }
public string Subject { get; set; }
public bool IsBodyHtml { get; set; }
public MailPriority Priority { get; set; }
private List<EmbeddedMailObject> m_EmbeddedObjects;
#endregion
#region action methods
public MailMessage CreateMailMessage(string recipients, ReplacementCollection replacements)
{
return CreateMailMessage((string)null, recipients, replacements, null);
}
public MailMessage CreateMailMessage(string recipients, ReplacementCollection replacements, IEnumerable<Attachment> attachments)
{
return CreateMailMessage((string)null, recipients, replacements, attachments);
}
public MailMessage CreateMailMessage(string body, string recipients, ReplacementCollection replacements)
{
return CreateMailMessage(body, recipients, replacements, null);
}
public MailMessage CreateMailMessage(string body, string recipients, ReplacementCollection replacements, IEnumerable<Attachment> attachments)
{
if (body == null && !string.IsNullOrEmpty(this.BodyFileName))
{
body = File.ReadAllText(GetFullBodyFileName());
}
string from = this.From;
if (string.IsNullOrEmpty(from))
{
from = GetDefaultFrom();
}
from = ApplyReplacements(from, replacements);
if (recipients != null)
{
recipients = ApplyEmailReplacement(ApplyReplacements(recipients.Replace(';', ','), replacements), from, EmailReplacementType.From);
}
string cc = this.CC;
if (cc != null)
{
cc = ApplyEmailReplacement(ApplyReplacements(cc.Replace(';', ','), replacements), from, EmailReplacementType.From);
}
string bcc = this.Bcc;
if (bcc != null)
{
bcc = ApplyEmailReplacement(ApplyReplacements(bcc.Replace(';', ','), replacements), from, EmailReplacementType.From);
}
if (!string.IsNullOrEmpty(body))
{
//Body replacements
body = ApplyReplacements(body, replacements, this.IsBodyHtml);
body = ApplyEmailReplacement(body, from, EmailReplacementType.From, this.IsBodyHtml);
body = ApplyEmailReplacement(body, recipients, EmailReplacementType.To, this.IsBodyHtml);
body = ApplyEmailReplacement(body, cc, EmailReplacementType.CC, this.IsBodyHtml);
body = ApplyEmailReplacement(body, bcc, EmailReplacementType.Bcc, this.IsBodyHtml);
}
var message = new MailMessage() { From = new MailAddress(from), IsBodyHtml = this.IsBodyHtml, Priority = this.Priority };
try
{
foreach (var address in ParseRecipients(recipients))
{
message.To.Add(address);
}
foreach (var address in ParseRecipients(cc))
{
message.CC.Add(address);
}
foreach (var address in ParseRecipients(bcc))
{
message.Bcc.Add(address);
}
string subject = this.Subject;
if (string.IsNullOrEmpty(subject) && this.IsBodyHtml)
{
subject = ExtractSubjectFromHtmlBody(body);
}
if (!string.IsNullOrEmpty(subject))
{
//Subject replacements
subject = ApplyReplacements(subject, replacements);
subject = ApplyEmailReplacement(subject, from, EmailReplacementType.From);
subject = ApplyEmailReplacement(subject, recipients, EmailReplacementType.To);
subject = ApplyEmailReplacement(subject, cc, EmailReplacementType.CC);
subject = ApplyEmailReplacement(subject, bcc, EmailReplacementType.Bcc);
message.Subject = subject;
}
if (m_EmbeddedObjects != null && m_EmbeddedObjects.Count != 0)
{
message.AlternateViews.Add(GetAlternateView(body));
}
else if (!string.IsNullOrEmpty(body))
{
message.Body = body;
}
if (attachments != null)
{
foreach (var attachment in attachments)
{
message.Attachments.Add(attachment);
}
}
}
catch
{
message.Dispose();
throw;
}
return message;
}
public MailMessage CreateMailMessage(Stream body, string recipients, ReplacementCollection replacements)
{
return CreateMailMessage(body, recipients, replacements, null);
}
public MailMessage CreateMailMessage(Stream body, string recipients, ReplacementCollection replacements, IEnumerable<Attachment> attachments)
{
string bodyText = null;
if (body != null)
{
using (var reader = new StreamReader(body))
{
bodyText = reader.ReadToEnd();
}
}
return CreateMailMessage(bodyText, recipients, replacements, attachments);
}
public void Send(string recipients, ReplacementCollection replacements)
{
using (var msg = CreateMailMessage((string)null, recipients, replacements, null))
{
var client = new SmtpClient();
client.Send(msg);
}
}
public void Send(string recipients, ReplacementCollection replacements, IEnumerable<Attachment> attachments)
{
using (var msg = CreateMailMessage((string)null, recipients, replacements, attachments))
{
var client = new SmtpClient();
client.Send(msg);
}
}
public void Send(string body, string recipients, ReplacementCollection replacements)
{
using (var msg = CreateMailMessage(body, recipients, replacements, null))
{
var client = new SmtpClient();
client.Send(msg);
}
}
public void Send(string body, string recipients, ReplacementCollection replacements, IEnumerable<Attachment> attachments)
{
using (var msg = CreateMailMessage(body, recipients, replacements, attachments))
{
var client = new SmtpClient();
client.Send(msg);
}
}
public void Send(Stream body, string recipients, ReplacementCollection replacements)
{
using (var msg = CreateMailMessage(body, recipients, replacements, null))
{
var client = new SmtpClient();
client.Send(msg);
}
}
public void Send(Stream body, string recipients, ReplacementCollection replacements, IEnumerable<Attachment> attachments)
{
using (var msg = CreateMailMessage(body, recipients, replacements, attachments))
{
var client = new SmtpClient();
client.Send(msg);
}
}
#endregion
#region property getters/setters
public List<EmbeddedMailObject> EmbeddedObjects
{
get
{
if (m_EmbeddedObjects == null)
{
m_EmbeddedObjects = new List<EmbeddedMailObject>();
}
return m_EmbeddedObjects;
}
set { m_EmbeddedObjects = value; }
}
#endregion
#region private member functions
private static string ApplyReplacements(string str, ReplacementCollection replacements, bool IsHtml)
{
if (!string.IsNullOrEmpty(str) && replacements != null)
{
foreach (var Item in replacements)
{
string Name = Item.Name.StartsWith("<%", StringComparison.Ordinal) ? Item.Name : "<%" + Item.Name + "%>";
string Value = Item.Value ?? "";
if (IsHtml)
{
if (Item.HtmlEncoding)
{
Value = Regex.Replace(System.Web.HttpUtility.HtmlEncode(Value), "\r\n|\r|\n", "<br />");
}
str = Regex.Replace(str, System.Web.HttpUtility.HtmlEncode(Name), Value, RegexOptions.IgnoreCase);
}
str = Regex.Replace(str, Name, Value, RegexOptions.IgnoreCase);
}
}
return str;
}
private static string ApplyReplacements(string str, ReplacementCollection replacements)
{
return ApplyReplacements(str, replacements, false);
}
private static string ApplyEmailReplacement(string str, string addresses, EmailReplacementType type, bool isHtml)
{
if (!string.IsNullOrEmpty(str))
{
switch (type)
{
case EmailReplacementType.From:
MailAddress from = null;
if (addresses != null)
{
from = new MailAddress(addresses);
}
str = Regex.Replace(str, "<%From%>", from == null ? "" : from.Address, RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%FromDisplayName%>", from == null ? "" : string.IsNullOrEmpty(from.DisplayName) ? from.Address : from.DisplayName, RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%FromFullName%>", addresses ?? "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%FromFullAddress%>", addresses ?? "", RegexOptions.IgnoreCase);
if (isHtml)
{
str = Regex.Replace(str, "<%From%>", from == null ? "" : from.Address, RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%FromDisplayName%>", from == null ? "" : string.IsNullOrEmpty(from.DisplayName) ? from.Address : from.DisplayName, RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%FromFullName%>", addresses ?? "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%FromFullAddress%>", addresses ?? "", RegexOptions.IgnoreCase);
}
break;
case EmailReplacementType.To:
var to = ParseRecipients(addresses);
str = Regex.Replace(str, "<%Recipients%>", string.Join(",", (from i in to select i.Address).ToArray()), RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%RecipientsDisplayName%>", string.Join(",", (from i in to select string.IsNullOrEmpty(i.DisplayName) ? i.Address : i.DisplayName).ToArray()), RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%RecipientsFullName%>", addresses ?? "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%RecipientsAddress%>", addresses ?? "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%To%>", string.Join(",", (from i in to select i.Address).ToArray()), RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%ToDisplayName%>", string.Join(",", (from i in to select string.IsNullOrEmpty(i.DisplayName) ? i.Address : i.DisplayName).ToArray()), RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%ToFullName%>", addresses ?? "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%ToFullAddress%>", addresses ?? "", RegexOptions.IgnoreCase);
if (isHtml)
{
str = Regex.Replace(str, "<%Recipients%>", string.Join(",", (from i in to select i.Address).ToArray()), RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%RecipientsDisplayName%>", string.Join(",", (from i in to select string.IsNullOrEmpty(i.DisplayName) ? i.Address : i.DisplayName).ToArray()), RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%RecipientsFullName%>", addresses ?? "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%RecipientsFullAddress%>", addresses ?? "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%To%>", string.Join(",", (from i in to select i.Address).ToArray()), RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%ToDisplayName%>", string.Join(",", (from i in to select string.IsNullOrEmpty(i.DisplayName) ? i.Address : i.DisplayName).ToArray()), RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%ToFullName%>", addresses ?? "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%ToFullAddress%>", addresses ?? "", RegexOptions.IgnoreCase);
}
break;
case EmailReplacementType.CC:
var cc = ParseRecipients(addresses);
str = Regex.Replace(str, "<%CC%>", string.Join(",", (from i in cc select i.Address).ToArray()), RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%CCDisplayName%>", string.Join(",", (from i in cc select string.IsNullOrEmpty(i.DisplayName) ? i.Address : i.DisplayName).ToArray()), RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%CCFullName%>", addresses ?? "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%CCFullAddress%>", addresses ?? "", RegexOptions.IgnoreCase);
if (isHtml)
{
str = Regex.Replace(str, "<%CC%>", string.Join(",", (from i in cc select i.Address).ToArray()), RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%CCDisplayName%>", string.Join(",", (from i in cc select string.IsNullOrEmpty(i.DisplayName) ? i.Address : i.DisplayName).ToArray()), RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%CCFullName%>", addresses ?? "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%CCFullAddress%>", addresses ?? "", RegexOptions.IgnoreCase);
}
break;
case EmailReplacementType.Bcc:
var bcc = ParseRecipients(addresses);
str = Regex.Replace(str, "<%Bcc%>", string.Join(",", (from i in bcc select i.Address).ToArray()), RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%BccDisplayName%>", string.Join(",", (from i in bcc select string.IsNullOrEmpty(i.DisplayName) ? i.Address : i.DisplayName).ToArray()), RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%BccFullName%>", addresses ?? "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%BccFullAddress%>", addresses ?? "", RegexOptions.IgnoreCase);
if (isHtml)
{
str = Regex.Replace(str, "<%Bcc%>", string.Join(",", (from i in bcc select i.Address).ToArray()), RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%BccDisplayName%>", string.Join(",", (from i in bcc select string.IsNullOrEmpty(i.DisplayName) ? i.Address : i.DisplayName).ToArray()), RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%BccFullName%>", addresses ?? "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, "<%BccFullAddress%>", addresses ?? "", RegexOptions.IgnoreCase);
}
break;
}
}
return str;
}
private static string ApplyEmailReplacement(string str, string addresses, EmailReplacementType type)
{
return ApplyEmailReplacement(str, addresses, type, false);
}
private AlternateView GetAlternateView(string body)
{
string mediaType = this.IsBodyHtml ? "text/html" : "text/plain";
AlternateView item = AlternateView.CreateAlternateViewFromString(body, null, mediaType);
foreach (var obj in m_EmbeddedObjects)
{
string path = obj.FileName;
if (string.IsNullOrEmpty(path))
{
throw new InvalidOperationException("Missing FileName in EmbeddedMailObject.");
}
if (!Path.IsPathRooted(path) && !string.IsNullOrEmpty(this.BodyFileName))
{
string bodyFileName = GetFullBodyFileName();
path = Path.Combine(Path.GetDirectoryName(bodyFileName), path);
}
LinkedResource resource = new LinkedResource(path) { ContentId = obj.Name };
try
{
resource.ContentType.Name = Path.GetFileName(path);
item.LinkedResources.Add(resource);
}
catch
{
resource.Dispose();
throw;
}
}
return item;
}
private static string ExtractSubjectFromHtmlBody(string body)
{
if (body == null)
{
return null;
}
int index = -1;
int index2 = -1;
int index3 = -1;
var sb = new System.Text.StringBuilder();
foreach (string line in ReadBodyLines(body))
{
if (index == -1)
{
index = line.IndexOf("<head>", StringComparison.OrdinalIgnoreCase);
if (index == -1)
{
continue;
}
}
if (index2 == -1)
{
index2 = line.IndexOf("<title>", index, StringComparison.OrdinalIgnoreCase);
if (index2 == -1)
{
index2 = line.IndexOf("</head>", index, StringComparison.OrdinalIgnoreCase);
if (index2 != -1)
{
break;
}
continue;
}
}
index3 = line.IndexOf("</title>", index2, StringComparison.OrdinalIgnoreCase);
if (index3 != -1)
{
if (index2 != 0) //line with "<title>"
{
sb.Append(line.Substring(index2 + "<title>".Length, index3 - index2 - "<title>".Length));
break;
}
sb.Append(line.Substring(0, index3));
break;
}
if (index2 != 0) //line with "<title>"
{
sb.Append(line.Substring(index2 + "<title>".Length));
index2 = 0;
continue;
}
sb.Append(line);
}
string subject = System.Web.HttpUtility.HtmlDecode(sb.ToString().Trim());
return subject.Length == 0 ? null : subject;
}
private string GetFullBodyFileName()
{
string path = this.BodyFileName;
if (!Path.IsPathRooted(path))
{
string mailTemplateRoot = System.IO.Path.GetDirectoryName((System.Reflection.Assembly.GetEntryAssembly() ?? System.Reflection.Assembly.GetExecutingAssembly()).Location);
path = Path.Combine(mailTemplateRoot, path);
}
return path;
}
private static IEnumerable<string> ReadBodyLines(string body)
{
using (var reader = new StringReader(body))
{
while (true)
{
string line = reader.ReadLine();
if (line == null)
{
yield break;
}
yield return line;
}
}
}
private static string GetDefaultFrom()
{
var smtpCfg = (SmtpSection)System.Configuration.ConfigurationManager.GetSection("system.net/mailSettings/smtp");
if (smtpCfg == null || smtpCfg.Network == null || string.IsNullOrEmpty(smtpCfg.From))
{
throw new InvalidOperationException("From address is not specified.");
}
return smtpCfg.From;
}
private static IEnumerable<MailAddress> ParseRecipients(string addresses)
{
if (string.IsNullOrEmpty(addresses))
{
yield break;
}
for (int i = 0; i < addresses.Length; i++)
{
yield return ParseMailAddress(addresses, ref i);
}
}
private static MailAddress ParseMailAddress(string addresses, ref int i)
{
int index = addresses.IndexOfAny(new[] { '"', ',' }, i);
if (index != -1 && addresses[index] == '"')
{
index = addresses.IndexOf('"', index + 1);
if (index == -1)
{
throw new FormatException("Invalid mail address format");
}
index = addresses.IndexOf(',', index + 1);
}
if (index == -1)
{
index = addresses.Length;
}
var address = new MailAddress(addresses.Substring(i, index - i).Trim(' ', '\t'));
i = index;
return address;
}
#endregion
}
#region EmbeddedMailObject
internal sealed class EmbeddedMailObject
{
#region member varible and default property initialization
public string Name { get; set; }
public string FileName { get; set; }
#endregion
#region constructors and destructors
public EmbeddedMailObject(string name, string fileName)
{
this.Name = name;
this.FileName = fileName;
}
#endregion
}
#endregion
#region Replacement, ReplacementCollection
internal class Replacement
{
#region constructors and destructors
internal Replacement()
{
this.HtmlEncoding = true;
}
#endregion
#region member varible and default property initialization
public string Name { get; set; }
public string Value { get; set; }
public bool HtmlEncoding { get; set; }
#endregion
#region action methods
public override string ToString()
{
return string.Format(System.Globalization.CultureInfo.CurrentCulture, "{0}: {1})", this.Name, this.Value);
}
#endregion
}
internal class ReplacementCollection : IEnumerable<Replacement>, System.Collections.IEnumerable
{
#region member varible and default property initialization
private Dictionary<string, Replacement> ReplacementsDictionary;
#endregion
#region constructors and destructors
public ReplacementCollection()
{
this.ReplacementsDictionary = new Dictionary<string, Replacement>();
}
#endregion
#region action methods
public void Add(string name, string value)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
if (name.Length == 0)
{
throw new ArgumentException("name is empty string.", "name");
}
this.ReplacementsDictionary.Add(name, new Replacement() { Name = name, Value = value });
}
public void Add(string name, string value, bool htmlEncoding)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
if (name.Length == 0)
{
throw new ArgumentException("name is empty string.", "name");
}
this.ReplacementsDictionary.Add(name, new Replacement() { Name = name, Value = value, HtmlEncoding = htmlEncoding });
}
public bool Remove(string name)
{
return this.ReplacementsDictionary.Remove(name);
}
public IEnumerator<Replacement> GetEnumerator()
{
return this.ReplacementsDictionary.Values.GetEnumerator();
}
#endregion
#region property getters/setters
public int Count
{
get { return this.ReplacementsDictionary.Count; }
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
#endregion
}
Třída MailDefinition je k dispozici také ke stažení zde
A ještě si ukážeme příklad použití. Předpokládejme například následující HTML šablonu emailové zprávy:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style type="text/css">
p.MsoNormal {
margin-top: 0cm;
margin-right: 0cm;
margin-bottom: 10.0pt;
margin-left: 0cm;
line-height: 115%;
font-size: 11.0pt;
font-family: "Calibri","sans-serif";
}
a:link {
color: blue;
text-decoration: underline;
text-underline: single;
}
</style>
<title>Potvrzení přijetí objednávky č. <%CisloObjednavky%></title>
</head>
<body>
<p class="MsoNormal">
Dobrý den,<br />
děkujeme, že jste nás kontaktovali.<br />
Toto je automatická zpráva potvrzující přijetí vaší objednávky. Objednávka je registrovana pod číslem <%CisloObjednavky%>.</p>
<p class="MsoNormal"></p>
<p class="MsoNormal">
<b style="mso-bidi-font-weight:normal">Objednávka byla přijata s těmito údaji:</b></p>
<p class="MsoNormal">
Číslo objednávky: <span style="mso-tab-count:1">
<%CisloObjednavky%></span><br />
Stav objednávky:<span style="mso-tab-count:1">
<%StavObjednavky%></span></p>
<p class="MsoNormal"></p>
<p class="MsoNormal">
Stav objednávky můžete sledovat přímo v systému na adrese: <%Link%> </p>
<p class="MsoNormal"></p>
<p class="MsoNormal">
Děkujeme za Vaši důvěru a těšíme se na další spolupráci.</p>
<p class="MsoNormal">
S pozdravem,<br />
Obchodní tým</p>
<p class="MsoNormal">
Tento e-mail je generován automaticky. Prosím, neodpovídejte na něj (adresa
<a href="mailto:<%From%>"><%From%></a> není monitorována).</p>
</body>
</html>
Pokud budeme mít tuto šablonu umístěnou přímo v resource aplikace (pod identifikátorem PrijetiObjednavkyKlient) bude kód pro odeslání emailové zprávy například následující:
var data = GetObjednavkaData(IDObjednavky);
//Odeslání emailové zprávy klientovi
var replacements = new ReplacementCollection()
{
{ "CisloObjednavky", data.CisloObjednavky.ToString() },
{ "StavObjednavky", data.StavObjednavky },
{ "Link", WebApplicationUtil.GetAbsoluteUrl("~/") }
};
var recipients = new System.Net.Mail.MailAddress(data.Email, data.KontaktniOsoba).ToString();
var maildef = new MailDefinition() { IsBodyHtml = true };
maildef.Send(Properties.Resources.PrijetiObjednavkyKlient, recipients, replacements);
Metoda GetObjednavkaData zde vrací objekt obsahující vlastnosti CisloObjednavky, StavObjednavky, Email a KontaktniOsoba s konkrétními daty pro mail. Pomocná třída WebApplicationUtil resp. její metoda GetAbsoluteUrl zde vrací absolutní URL výchozí stránky aktuální web aplikace.
Třída WebApplicationUtil je ke stažení k dispozici zde