Search code examples
c#asp.netc#-4.0smtpemail-attachments

Attachments stream turns to 0 Byte when sending to multiple email addresses in loop


I am sending multiple attachments to email addresses in a loop. Attachment is properly getting send to first email address in the list but when it loops ahead for other email addresses in list, the attachment stream in parameter - model becomes 0 in length i. e. 0 bytes.

View Model Code :

public class BulkMailViewModel
{
    public string EmailTo { get; set; }

    public string EmailSubject { get; set; }

    public string EmailBody { get; set; }

    public List<HttpPostedFileBase> Attachments { get; set; }

    public BulkMailViewModel()
    {
        Attachments = new List<HttpPostedFileBase>();
    }
}

Controller Code : Below Controller method runs the loop for email addressed to send email.

public async Task<ActionResult> SendEmail(BulkMailViewModel model)
    {
        List<HttpPostedFileBase> attachments = new List<HttpPostedFileBase>();
        bool isEmailSentMain = true;
        if (model.Attachments != null && model.Attachments.Any())
        {
            foreach (var attachment in model.Attachments)
            {
                if (attachment != null)
                {
                    attachments.Add(attachment);
                }
            }
        }
        string emailContent = System.Uri.UnescapeDataString(model.EmailBody);
        try
        {
            List<string> clientEmails = new List<string>() { };

            clientEmails.Add("abc@abc.com");
            clientEmails.Add("pqr@pqr.com");

            foreach (var email in clientEmails)
            {
                try
                {
                    bool isEmailSent = false;
                    if (email != null && email != "")
                    {
                        isEmailSent = await SendBulkEmailAsync(email, model.EmailSubject, emailContent, attachments, true);

                        if (!isEmailSent)
                        {
                            isEmailSentMain = false;
                        }
                    }
                }
                catch (Exception e)
                {
                    isEmailSentMain = false;
                    return Json(new { status = isEmailSentMain, type = "continue", message = "Error while sending Email." });
                }
            }

        }

        catch (Exception e)
        {
            return Json(new { status = false, message = e.ToString()});
        }
    }

Mail method Code : This method actually sends the mail.

public async Task<bool> SendBulkEmailAsync(string emailTo, string emailSubject, string emailContent, List<HttpPostedFileBase> attachmentList, bool isBodyHtml = false)
    {
        List<HttpPostedFileBase> attachments = attachmentList;
        using (SmtpClient smtp = new SmtpClient()
        {
            //My SMTP Settings
        })

        using (var message = new MailAddress("email@abc.com", emailTo))
        {

            if (attachments != null)
            {
                foreach (var attach in attachments)
                {
                    string strFileName = System.IO.Path.GetFileName(attach.FileName);
                    attach.InputStream.Position = 0;
                    Attachment attachFile =
                    new Attachment(attach.InputStream, strFileName, attach.ContentType);
                    message.Attachments.Add(attachFile);
                }
            }
            message.Subject = emailSubject;
            message.Body = emailContent;
            message.IsBodyHtml = isBodyHtml;
            await smtp.SendMailAsync(message);

            return true;
        }
    }

Can anybody help with this?


Solution

  • You must clone the content of the attach.InputStream in a local stream to avoid it to be closed by SendMailAsync:

                foreach (var attach in attachments)
                {
                    string strFileName = System.IO.Path.GetFileName(attach.FileName);
                    attach.InputStream.Position = 0;
                    MemoryStream tempStream = new MemoryStream();
                    attach.InputStream.CopyTo(tempStream);
                    tempStream.Position = 0;
                    Attachment attachFile =
                    new Attachment(tempStream, strFileName, attach.ContentType);
                    message.Attachments.Add(attachFile);
                }