AddAttachment from MemoryStream

2019-04-30 19:19发布

问题:

The SendGrid API docs specify you can add attachments from a Stream. The example it gives uses a FileStream object.

I have some blobs in Azure Storage which I'd like to email as attachments. To achieve this I'm trying to use a MemoryStream:

var getBlob = blobContainer.GetBlobReferenceFromServer(fileUploadLink.Name);
if(getBlob != null)
{
  // Get file as a stream
  MemoryStream memoryStream = new MemoryStream();
  getBlob.DownloadToStream(memoryStream);
  emailMessage.AddAttachment(memoryStream, fileUploadLink.Name);
}
emailTransport.Deliver(emailMessage);

It sends fine but when the email arrives, the attachment appears to be there but it's actually empty. Looking at the email source, there is no content for the attachment.

Is using a MemoryStream a known limitation when using the SendGrid C# API to send attachments? Or should I be approaching this in some other way?

回答1:

You probably just need to reset the stream position back to 0 after you call DownloadToStream:

var getBlob = blobContainer.GetBlobReferenceFromServer(fileUploadLink.Name);

if (getBlob != null)
{
    var memoryStream = new MemoryStream();

    getBlob.DownloadToStream(memoryStream);
    memoryStream.Seek(0,SeekOrigin.Begin); // Reset stream back to beginning
    emailMessage.AddAttachment(memoryStream, fileUploadLink.Name);
}

emailTransport.Deliver(emailMessage);

You might want to check who cleans up the stream as well and if they don't you should dispose of it after you've called Deliver().



回答2:

According to their API, they have implemented void AddAttachment(Stream stream, String name). You are probably using a MemoryStream which you have written to before. I suggest resetting the position inside the stream to the beginning, like:

memoryStream.Seek(0, SeekOrigin.Begin);


回答3:

I ended up with the following which fixed the issue for me:

fileByteArray = new byte[getBlob.Properties.Length];
getBlob.DownloadToByteArray(fileByteArray, 0);
attachmentFileStream = new MemoryStream(fileByteArray);
emailMessage.AddAttachment(attachmentFileStream, fileUploadLink.Name);


回答4:

The thread is a bit old, but I use a varient with NReco PDF converter:

    private async Task SendGridasyncBid(string from, string to, string  displayName, string subject, **byte[] PDFBody**, string TxtBody, string HtmlBody)
        {
            ...
            var myStream =  new System.IO.MemoryStream(**PDFBody**);
            myStream.Seek(0, SeekOrigin.Begin);
            myMessage.AddAttachment(myStream, "NewBid.pdf");

            ...
        }

convert the html to pdf and return it instead of writing it for download...

    private byte[] getHTML(newBidViewModel model)
    {
        string strHtml = ...;

        HtmlToPdfConverter pdfConverter = new HtmlToPdfConverter();
        pdfConverter.CustomWkHtmlArgs = "--page-size Letter";

        var pdfBytes = pdfConverter.GeneratePdf(strHtml);

        return **pdfBytes**;
    }

I am not sure how efficient this is, but it is working for me and I hope it helps someone else get their attachments figured out.