Прикрепите файл из MemoryStream к MailMessage на C #

113

Я пишу программу для прикрепления файла к электронной почте. В настоящее время я сохраняю файл FileStreamна диск, а затем использую

System.Net.Mail.MailMessage.Attachments.Add(
    new System.Net.Mail.Attachment("file name")); 

Я не хочу хранить файл на диске, я хочу сохранить файл в памяти и передать его из потока памяти Attachment.

Заин Али
источник

Ответы:

104

Вот пример кода.

System.IO.MemoryStream ms = new System.IO.MemoryStream();
System.IO.StreamWriter writer = new System.IO.StreamWriter(ms);
writer.Write("Hello its my sample file");
writer.Flush();
writer.Dispose();
ms.Position = 0;

System.Net.Mime.ContentType ct = new System.Net.Mime.ContentType(System.Net.Mime.MediaTypeNames.Text.Plain);
System.Net.Mail.Attachment attach = new System.Net.Mail.Attachment(ms, ct);
attach.ContentDisposition.FileName = "myFile.txt";

// I guess you know how to send email with an attachment
// after sending email
ms.Close();

Редактировать 1

Вы можете указать другие типы файлов с помощью System.Net.Mime.MimeTypeNames, например System.Net.Mime.MediaTypeNames.Application.Pdf

В зависимости от типа Mime вам необходимо указать правильное расширение в FileName, например"myFile.pdf"

Waqas Raja
источник
Я использую PDF. Как передать этот тип в System.Net.Mime.ContentType ct = new System.Net.Mime.ContentType (System.Net.Mime.MediaTypeNames.Text.Plain);
Zain Ali
3
Вам нужно использоватьSystem.Net.Mime.MediaTypeNames.Application.Pdf
Waqas Raja
5
writer.Disopose()было слишком рано для моего решения, но все остальное - отличный пример.
Казимеж Явор
7
Я почти уверен, что ms.Position = 0;перед созданием вложения должен быть .
Кенни Эвитт
94

Немного позднее вступление - но, надеюсь, все же полезно для кого-то там: -

Вот упрощенный фрагмент для отправки строки в памяти в виде вложения электронной почты (в данном конкретном случае файл CSV).

using (var stream = new MemoryStream())
using (var writer = new StreamWriter(stream))    // using UTF-8 encoding by default
using (var mailClient = new SmtpClient("localhost", 25))
using (var message = new MailMessage("me@example.com", "you@example.com", "Just testing", "See attachment..."))
{
    writer.WriteLine("Comma,Seperated,Values,...");
    writer.Flush();
    stream.Position = 0;     // read from the start of what was written

    message.Attachments.Add(new Attachment(stream, "filename.csv", "text/csv"));

    mailClient.Send(message);
}

StreamWriter и базовый поток не следует удалять до тех пор, пока сообщение не будет отправлено (во избежание ObjectDisposedException: Cannot access a closed Stream).

спокойное озеро
источник
30
Для любых новичков ключевым моментом для меня была установкаstream.position = 0;
mtbennett
3
+1 за правильное использование using () - чего-то, чего всегда не хватает в примерах и фрагментах в Интернете (включая принятый ответ на этот вопрос).
Джей Керидо
2
Благодаря @mtbennet это тоже была моя проблема - настройка stream.Position=0.
Icarus
Что на самом деле здесь делает установка типа MIME? Что-нибудь для почтового клиента?
xr280xr
@ xr280xr - Верно. Этот параметр на самом деле не является обязательным, но его включение должно помочь почтовому клиенту получателя разумно обрабатывать вложение. docs.microsoft.com/en-us/dotnet/api/…
tranquil tarn
28

Поскольку я нигде не мог найти подтверждения этому, я проверил, удалит ли удаление MailMessage и / или объекта Attachment загруженный в них поток, как я ожидал.

В следующем тесте действительно видно, что при удалении MailMessage все потоки, используемые для создания вложений, также будут удалены. Итак, пока вы распоряжаетесь своим MailMessage, потоки, которые пошли на его создание, не нуждаются в дополнительной обработке.

MailMessage mail = new MailMessage();
//Create a MemoryStream from a file for this test
MemoryStream ms = new MemoryStream(File.ReadAllBytes(@"C:\temp\test.gif"));

mail.Attachments.Add(new System.Net.Mail.Attachment(ms, "test.gif"));
if (mail.Attachments[0].ContentStream == ms) Console.WriteLine("Streams are referencing the same resource");
Console.WriteLine("Stream length: " + mail.Attachments[0].ContentStream.Length);

//Dispose the mail as you should after sending the email
mail.Dispose();
//--Or you can dispose the attachment itself
//mm.Attachments[0].Dispose();

Console.WriteLine("This will throw a 'Cannot access a closed Stream.' exception: " + ms.Length);
тимин
источник
Блин, это умно. Одна строка кода, и вы можете добавить файл изображения к электронному письму в качестве вложения. Отличный совет!
Майк Гледхилл,
Я бы хотел, чтобы это было задокументировано. Ваш тест / проверка этого поведения полезен, но без официальной документации трудно поверить, что так будет всегда. В любом случае, спасибо за тестирование.
Лукас,
Good Effort and Research @thymine
vibs2006
1
это как бы задокументировано, если есть ссылка на источник. mailmessage.dispose вызывает attachments.dispose, который по очереди вызывает dispose для каждого вложения, которое в mimepart закрывает поток .
Cee McSharpface
Спасибо. Я думал, что это должно делать почтовое сообщение, и оно нужно, потому что я создаю свои сообщения в классах, отличных от тех, в которые оно фактически отправлено.
xr280xr
20

Если вы действительно хотите добавить .pdf, я счел необходимым установить позицию потока памяти на ноль.

var memStream = new MemoryStream(yourPdfByteArray);
memStream.Position = 0;
var contentType = new System.Net.Mime.ContentType(System.Net.Mime.MediaTypeNames.Application.Pdf);
var reportAttachment = new Attachment(memStream, contentType);
reportAttachment.ContentDisposition.FileName = "yourFileName.pdf";
mailMessage.Attachments.Add(reportAttachment);
Джейсон Диммик
источник
Потратьте часы на отправку PDF-файла, это сработало как шарм!
dijam 01
12

Если все, что вы делаете, это прикрепляете строку, вы можете сделать это всего за две строки:

mail.Attachments.Add(Attachment.CreateAttachmentFromString("1,2,3", "text/csv");
mail.Attachments.Last().ContentDisposition.FileName = "filename.csv";

Мне не удалось заставить свою работать, используя наш почтовый сервер с StreamWriter.
Я думаю, возможно, потому, что с StreamWriter вам не хватает информации о свойствах файла, и, возможно, нашему серверу не понравилось то, что отсутствовало.
С помощью Attachment.CreateAttachmentFromString () он создал все, что мне было нужно, и отлично работает!

В противном случае я бы предложил взять ваш файл, который находится в памяти, и открыть его с помощью MemoryStream (byte []), и пропустить StreamWriter все вместе.

MikeTeeVee
источник
2

Я столкнулся с этим вопросом, потому что мне нужно было прикрепить файл Excel, который я генерирую с помощью кода и доступен как MemoryStream. Я мог прикрепить его к почтовому сообщению, но он был отправлен как файл размером 64 байта, а не размером ~ 6 КБ, как предполагалось. Итак, решение, которое сработало для меня, было следующее:

MailMessage mailMessage = new MailMessage();
Attachment attachment = new Attachment(myMemorySteam, new ContentType(MediaTypeNames.Application.Octet));

attachment.ContentDisposition.FileName = "myFile.xlsx";
attachment.ContentDisposition.Size = attachment.Length;

mailMessage.Attachments.Add(attachment);

Установка значения attachment.ContentDisposition.SizeРазрешить мне отправлять сообщения с правильным размером вложения.

ilForna
источник
2

используйте ДРУГОЙ ОТКРЫТЫЙ поток памяти:

пример для lauch pdf и отправки pdf в MVC4 C # Controller

        public void ToPdf(string uco, int idAudit)
    {
        Response.Clear();
        Response.ContentType = "application/octet-stream";
        Response.AddHeader("content-disposition", "attachment;filename= Document.pdf");
        Response.Buffer = true;
        Response.Clear();

        //get the memorystream pdf
        var bytes = new MisAuditoriasLogic().ToPdf(uco, idAudit).ToArray();

        Response.OutputStream.Write(bytes, 0, bytes.Length);
        Response.OutputStream.Flush();

    }


    public ActionResult ToMail(string uco, string filter, int? page, int idAudit, int? full) 
    {
        //get the memorystream pdf
        var bytes = new MisAuditoriasLogic().ToPdf(uco, idAudit).ToArray();

        using (var stream = new MemoryStream(bytes))
        using (var mailClient = new SmtpClient("**YOUR SERVER**", 25))
        using (var message = new MailMessage("**SENDER**", "**RECEIVER**", "Just testing", "See attachment..."))
        {

            stream.Position = 0;

            Attachment attach = new Attachment(stream, new System.Net.Mime.ContentType("application/pdf"));
            attach.ContentDisposition.FileName = "test.pdf";

            message.Attachments.Add(attach);

            mailClient.Send(message);
        }

        ViewBag.errMsg = "Documento enviado.";

        return Index(uco, filter, page, idAudit, full);
    }
Анхель Ибаньес
источник
stream.Position=0; это линия, которая мне помогла. без него мой атрибут был всего лишь 504 байта из некоторых килобайт,
Абдул Хамид
-6

Думаю, этот код вам поможет:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Net.Mail;

public partial class _Default : System.Web.UI.Page
{
  protected void Page_Load(object sender, EventArgs e)
  {

  }

  protected void btnSubmit_Click(object sender, EventArgs e)
  {
    try
    {
      MailAddress SendFrom = new MailAddress(txtFrom.Text);
      MailAddress SendTo = new MailAddress(txtTo.Text);

      MailMessage MyMessage = new MailMessage(SendFrom, SendTo);

      MyMessage.Subject = txtSubject.Text;
      MyMessage.Body = txtBody.Text;

      Attachment attachFile = new Attachment(txtAttachmentPath.Text);
      MyMessage.Attachments.Add(attachFile);

      SmtpClient emailClient = new SmtpClient(txtSMTPServer.Text);
      emailClient.Send(MyMessage);

      litStatus.Text = "Message Sent";
    }
    catch (Exception ex)
    {
      litStatus.Text = ex.ToString();
    }
  }
}
r12
источник
5
-1 Этот ответ загружает вложение с диска с помощью конструктора Attachment (string fileName). OP конкретно заявляет, что он не хочет загружаться с диска. Кроме того, это просто код, скопированный из ссылки в ответе Red Swan.
Walter Stabosz
Поток attachFile также не удален
Самех