آموزش ارسال ایمیل در MVC

در این مقاله نحوه ارسال ایمیل در برنامه MVC را خواهید آموخت.

  آموزش ارسال ایمیل در MVC

در این مقاله نحوه ارسال ایمیل توسط SMTP (پروتکل ساده ارسال ایمیل) را خواهید آموخت. راه های زیاد دیگری برای ارسال ایمیل وجود دارند از قبیل : POP3 IMAP WEB SERVICE و غیره.

NET. دارای کتابخانه ای برای ارسال ایمیل به صورت SMTP می باشد. این در فضای نام System.Net.Mail موجود است و دارای کلاس های کلیدی برای ساخت ایمیل و فرستادن آن به سرور SMTP برای ارسال می باشد. قبل از انجام کار با آنها شما باید به SMTP دسترسی پیدا کنید. ISP شما ممکن است این دسترسی را برای شما فراهم کرده باشد در غیر این صورت شما می توانید از سرویس های رایگانی مانند Gmail یا Outlook و Yahoo و غیره استفاده نمایید.

 

بیشترین استفاده برای ارسال ایمیل به کاربران سایت برای برقراری ارتباط و نزدیک تر شدن به آنها می باشد.

مراحل کار

ویژوال استادیو را باز کرده و یک پروژه از نوع MVC ایجاد نمایید. برای این کار مانند تصاویر زیر عمل کنید.

در پوشه Models یک کلاس با نام EmailFormModel ایجاد کرده و کدهای زیر را برای آن می نویسیم.

using System.ComponentModel.DataAnnotations;

namespace MVCEmail.Models
{
    public class EmailFormModel
    {
        [Required, Display(Name="Your name")]
        public string FromName { get; set; }
        [Required, Display(Name = "Your email"), EmailAddress]
        public string FromEmail { get; set; }
        [Required]
        public string Message { get; set; }
    }
}

 

در ویو موجود در پوشه Home با نام Contact کدهای زیر را می نویسیم.

@model MVCEmail.Models.EmailFormModel
@{
    ViewBag.Title = "Contact";
}
<h2>@ViewBag.Title.</h2>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    <h4>Send your comments.</h4>
    <hr />
    <div class="form-group">
        @Html.LabelFor(m => m.FromName, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.FromName, new { @class = "form-control" })
            @Html.ValidationMessageFor(m => m.FromName)
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.FromEmail, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.FromEmail, new { @class = "form-control" })
            @Html.ValidationMessageFor(m => m.FromEmail)
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.Message, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextAreaFor(m => m.Message, new { @class = "form-control" })
            @Html.ValidationMessageFor(m => m.Message)
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" class="btn btn-default" value="Send" />
        </div>
    </div>
}

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

 

فضای نام های زیر را به کنترلر Home اضافه نمایید.

using MVCEmail.Models;
using System.Net;
using System.Net.Mail;

 

همچنین برای متد Contact در کنترلر Home کدهای زیر را می نویسیم.

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Contact(EmailFormModel model)
{
    if (ModelState.IsValid)
    {
        var body = "<p>Email From: {0} ({1})</p><p>Message:</p><p>{2}</p>";
        var message = new MailMessage();
        message.To.Add(new MailAddress("recipient@gmail.com"));  // replace with valid value 
        message.From = new MailAddress("sender@outlook.com");  // replace with valid value
        message.Subject = "Your email subject";
        message.Body = string.Format(body, model.FromName, model.FromEmail, model.Message);
        message.IsBodyHtml = true;

        using (var smtp = new SmtpClient())
        {
            var credential = new NetworkCredential
            {
                UserName = "user@outlook.com",  // replace with valid value
                Password = "password"  // replace with valid value
            };
            smtp.Credentials = credential;
            smtp.Host = "smtp-mail.outlook.com";
            smtp.Port = 587;
            smtp.EnableSsl = true;
            await smtp.SendMailAsync(message);
            return RedirectToAction("Sent");
        }
    }
    return View(model);
}

 

یک متد با نام Sent مانند زیر به کنترلر Home اضافه می کنیم.

public ActionResult Sent()
{
    return View();
}


و در ویو آن داریم :
 

@{
    ViewBag.Title = "Sent";
}
<h2>Your message has been sent</h2>

 

شما با ساخت یک شیء MailMessage شروع می کنید. MailMessage کلاسی است برای معرفی ایمیل ارسالی می باشد. دریافت کنندگان ایمیل به عنوان مجموعه ای از شیء MailAddress می باشند. آنها در پروپرتی To از کلاس MailAddress قرار می گیرند. همچنین فرستنده ایمیل همان پروپرتی From از کلاس MailAddress می باشد. پروپرتی های Body و Subject که نیاز به توضیح نداشته و از نامشان مشخص است برای چه می باشند. به طور پیش فرض متن ایمیل ها به صورت متن ساده ساخته می شوند. اگر شما نیاز به ارسال ایمیل به صورت html دارید باید پروپرتی IsBodyHtml را True نمایید.

پس از ساخته شدن متن ایمیل، نیاز به ارسال آن داریم. کلاس SmtpClient برای انجام این کار می باشد. تنظیمات شیء SmtpClient اغلب جایی است که مشکلات در آن اتفاق می افتد پس لازم است تا شما از تنظیمات درست استفاده کنید.

معمولا این ها در Outlook و Gmail یکسان می باشند :

 

اگر شما از سرویس دیگری استفاده می کنید باید از سرویس گیرنده ویژگی های بالا را بررسی نمایید.

 

کدهای بالا کافی است اما دارای یک مشکل است. این مشکل این است که اگر شما آدرس ایمیل ارسالی را تغییر دهید باید این تغییرات را در سورس کد اعمال نمایید و این نیاز به دوباره کامپایل شدن و غیره دارد. و اگر شما بخواهید در قسمتهای مختلف برنامه به کاربر ایمیل ارسال نمایید لازم است تا این تغییرات را در همه آن قسمتها اعمال نمایید. برای حل این مشکل کافی است تا به Web.Config رفته و مانند زیر عمل نمایید :
 

<system.net>
  <mailSettings>
    <smtp from="you@outlook.com">
      <network host="smtp-mail.outlook.com" 
               port="587" 
               userName="you@outlook.com"
               password="password" 
               enableSsl="true" />
    </smtp>
  </mailSettings>
</system.net>

 

با انجام کارهای بالا کدهای مورد نیاز در کنترلر کمتر می شود. در این مثال کدهای متد Contact به صورت زیر می شوند :
 

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Contact(EmailFormModel model)
{
    if (ModelState.IsValid)
    {
        var body = "<p>Email From: {0} ({1})</p><p>Message:</p><p>{2}</p>";
        var message = new MailMessage();
        message.To.Add(new MailAddress("name@gmail.com")); //replace with valid value
        message.Subject = "Your email subject";
        message.Body = string.Format(body, model.FromName, model.FromEmail, model.Message);
        message.IsBodyHtml = true;
        using (var smtp = new SmtpClient())
        {
            await smtp.SendMailAsync(message);
            return RedirectToAction("Sent");
        }
    }
    return View(model);
}

 

در بالا همه تنظیمات Smtp حذف شده اند.

 

ارسال ایمیل به چند گیرنده (Multiple Recipients)

اگر ایمیلی که تصمیم به ارسال آن دارید را بخواهید به چند گیرنده بفرستید لازم است تا مانند زیر از شیء MailAddress چند بار استفاده کنید.

message.To.Add(new MailAddress("one@gmail.com"));
message.To.Add(new MailAddress("two@gmail.com"));
message.To.Add(new MailAddress("three@gmail.com"));

 

همچنین اگر بخواهید تا گیرنده های ایمیل نتوانند نام همدیگر را در لیست گیرندگان ببینند می توانید از پروپرتی Bcc مانند زیر استفاده نمایید :

message.Bcc.Add(new MailAddress("one@gmail.com"));
message.Bcc.Add(new MailAddress("two@gmail.com"));
message.Bcc.Add(new MailAddress("three@gmail.com"));

اضافه کردن فایل پیوست (Attachment)

برای پیوست کردن یک فایل به ایمیل ارسالی شما می توانید از پروپرتی Attachment مانند زیر استفاده نمایید.

message.Attachments.Add(new Attachment(HttpContext.Server.MapPath("~/App_Data/Test.docx")));

همچنین مانند زیر تغییراتی در ویو اعمال نمایید.(قسمتهای زردرنگ قسمتهایی هستند که باید به ویو اضافه شوند)

Contact.cshtml

@model MVCEmail.Models.EmailFormModel
@{
    ViewBag.Title = "Contact";
}
<h2>@ViewBag.Title.</h2>

@using (Html.BeginForm("Contact", "Home", null, FormMethod.Post, new {enctype = "multipart/form-data"}))
{
    @Html.AntiForgeryToken()
    <h4>Send your comments.</h4>
    <hr />
    <div class="form-group">
        @Html.LabelFor(m => m.FromName, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.FromName, new { @class = "form-control" })
            @Html.ValidationMessageFor(m => m.FromName)
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.FromEmail, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.FromEmail, new { @class = "form-control" })
            @Html.ValidationMessageFor(m => m.FromEmail)
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.Message, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextAreaFor(m => m.Message, new { @class = "form-control" })
            @Html.ValidationMessageFor(m => m.Message)
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.Upload, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            <input type="file" name="upload" />
        </div>
    </div>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" class="btn btn-default" value="Send" />
        </div>
    </div>
}

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

همچنین لازم است تا یک پروپرتی دیگر با نام Upload از نوع HttpPostedFileBase به مدل EmailFromModel اضافه کنیم :
 

using System.ComponentModel.DataAnnotations;
using System.Web;
namespace MVCEmail.Models
{
    public class EmailFormModel
    {
        [Required, Display(Name="Your name")]
        public string FromName { get; set; }
        [Required, Display(Name = "Your email"), EmailAddress]
        public string FromEmail { get; set; }
        [Required]
        public string Message { get; set; }
        public HttpPostedFileBase Upload { get; set; }
    }
}

و کار آخری که برای اضافه کردن فایل ضمیمه به ایمیل ارسالی باید انجام دهیم این است که تغییرات زیر را در متد contact موجود در کنترلر Home اعمال نماییم.

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Contact(EmailFormModel model)
{
    if (ModelState.IsValid)
    {
        var body = "<p>Email From: {0} ({1})</p><p>Message:</p><p>{2}</p>";
        var message = new MailMessage();
        message.To.Add(new MailAddress("name@gmail.com")); //replace with valid value
        message.Subject = "Your email subject";
        message.Body = string.Format(body, model.FromName, model.FromEmail, model.Message);
        message.IsBodyHtml = true;
        if (model.Upload != null && model.Upload.ContentLength > 0)
        {
            message.Attachments.Add(new Attachment(model.Upload.InputStream, Path.GetFileName(model.Upload.FileName)));
        }
        using (var smtp = new SmtpClient())
        {
            await smtp.SendMailAsync(message);
            return RedirectToAction("Sent");
        }
    }
    return View(model);
}

 

حال پروژه را Build و اجرا کرده و به صفحه Contact رفته و یک فایل آپلود می کنیم. ایمیل با فایل آپلودشده تولید خواهید شد.

کدی که به ویو اضافه کردید کنترل آپلود فایل را فراهم کرده و enctype فرم را به multipart/form-data تغییر می دهد که برای آپلود به سرور می باشد. همچنین ما در ویو مدل از نوع HttpPostedFileBase در پروپرتی Uplaod استفاده کردیم که برای ارسال فایل در NET. می باشد. سپس در کنترلر بررسی کردیم پروپرتی جدید مقدار دارد یا خیر.

 

اضافه کردن فایل پیوست از بانک اطلاعاتی

اگر شما فایلی در جدول بانک اطلاعاتی ذخیره کرده باشید آن فایل به صورت Byte ذخیره شده است. شما نیاز به تبدیل آن دارید.

کدهای زیر نحوه گرفتن محتوای یک فایل و تبدیل آن به Stream و ساخت فایل پیوست (Attachment) برای ایمیل ارسالی می باشد :

public ActionResult Index(int id)
{
    var file = db.Files.Find(id);
    Attachment attachment;
    using (var stream = new MemoryStream())
    {
        stream.Write(file.Content, 0, file.Content.Length - 1);
        attachment = new Attachment(stream, file.FileName);
    }
    var message = new MailMessage();
    message.Attachments.Add(attachment);

    // etc...
}

همچنین باید تغییرات زیر را در Web.Config انجام دهیم :

<system.net>
  <mailSettings>
    <smtp deliveryMethod="SpecifiedPickupDirectory">
      <specifiedPickupDirectory pickupDirectoryLocation="C:\MailDump"/>
    </smtp>
  </mailSettings>
</system.net>

 

پیام خطاهای رایج در ارسال ایمیل

5.5.1 Authentication Required

زمانی رخ می دهد که شما برنامه را authorised نکرده باشید.

The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.7.0 Must issue a STARTTLS command first

زمانی رخ می دهد که شما EnableSssl را True نکرده باشید اما ایمیل نیاز به Ssl داشته باشد. مقدار آن را True کرده و دوباره امتحان نمایید.

Mailbox unavailable. The server response was: 5.7.3 Requested action aborted; user not authenticated

نام کاربری و کلمه عبور صحیح نمی باشد یا DefaultCredentials روی True می باشد.