Вы используете потоки неправильно. Вам нужно использовать отдельный Stream
для каждого Attachment
.
В качестве хитрого трюка (я полагаю) вам не нужен промежуточный поток или буфер - но вы можете передавать потоки выгрузки файлов непосредственно конструкторам Attachment
, если MailMessage
будет отправлено до завершения жизненного цикла запросов / ответов ASP.NET . (Обратите внимание, что Attachment
становится владельцем потока, переданного в его конструктор, поэтому вам не нужно самостоятельно распоряжаться потоком вложения при условии, что родительский элемент MailMessage
также расположен ).
Также есть несколько вещей, которые выглядят неправильно в вашем коде (например, жесткое кодирование 3
для количества файлов) и выполнение await Task.Run( ... )
для не асинхронной операции.
Поскольку вы используете System.Web
версию ASP.NET (то есть , а не с использованием ASP.NET Core), я не рекомендую использовать какие-либо async
API, потому что это портит запрос / Жизненный цикл ответа.
Попробуйте это:
HttpFileCollectionBase addedFiles = ...
using( SmtpClient mailClient = new SmtpClient( smtpServer, Convert.ToInt16( smtpPort ) ) )
using( MailMessage emailMessage = new MailMessage( fromAddress, toAddress, subject, message ) )
{
if( addedFiles?.Count > 0 )
{
foreach( HttpPostedFileBase file in addedFiles )
{
Boolean isOK = ( file.FileName.EndsWith( ".pdf", StringComparison.OrdinalIgnoreCase ) || file.FileName.EndsWith( ".doc", StringComparison.OrdinalIgnoreCase ) ) && file.ContentLength > 0 && file.ContentLength < 10485760;
if( isOK )
{
Attachment att = new Attachment( file.InputStream, name: file.FileName );
emailMessage.Attachments.Add( att );
}
}
}
mailClient.Send( emailMessage );
}
Если вам нужно, чтобы MailMessage
пережил жизненный цикл запросов / ответов ASP.NET, или если вы хотите проверять или обрабатывать загруженные файлы перед их присоединением, то вам нужно будет буферизовать их по отдельности, например, так: :
HttpFileCollectionBase addedFiles = ...
using( SmtpClient mailClient = new SmtpClient( smtpServer, Convert.ToInt16( smtpPort ) ) )
using( MailMessage emailMessage = new MailMessage( fromAddress, toAddress, subject, message ) )
{
if( addedFiles?.Count > 0 )
{
foreach( HttpPostedFileBase file in addedFiles )
{
Boolean isOK = ( file.FileName.EndsWith( ".pdf", StringComparison.OrdinalIgnoreCase ) || file.FileName.EndsWith( ".doc", StringComparison.OrdinalIgnoreCase ) ) && file.ContentLength > 0 && file.ContentLength < 10485760;
if( isOK )
{
MemoryStream copy = new MemoryStream( capacity: file.ContentLength );
file.InputStream.CopyTo( copy );
// Rewind the stream, this is important! (You cannot rewind ASP.NET's file.InputStream, hence why we use a MemoryStream copy).
copy.Seek( 0, SeekOrigin.Begin );
DoSomethingWithFileStream( copy );
// Rewind the stream again, this is important!
copy.Seek( 0, SeekOrigin.Begin );
Attachment att = new Attachment( copy, name: file.FileName );
emailMessage.Attachments.Add( att );
}
}
}
mailClient.Send( emailMessage );
}