Problem:
The System.Net.Mail.MailMessage is badly missing the option of saving the Message as a file. Though there is a workaournd by using the SpecifiedPickupDirectory option of the SmtpClient to write the mail message ot the specific folder. This option however doesn't have flexibility in naming the files. In a multi-threaded parallel execution environment, it is difficult to identify and rename the specific files post writing to disk. There ought to be a better solution to handle this problem.
Solution:
You can extend the MailMessage class and add a Save method yourself. The Send method of the SmtpClient creates and uses MailWriter object to write out the mail message and it uses fileMailWriter when the SpecificPickupDirectory is specified as the DeliveryMethod. Create your own MailWriter object using FileStream and invoke the internal Send method, passing your MailWriter object. Check out this Code Project Article for more details. The code samples given there are for the C# language. Just in case you need, given below the same code for the Extension in VB.NET.
Imports System
Imports System.Net.Mail
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.IO
Imports System.Reflection
Imports System.Runtime.CompilerServices
Module MailMessageExtension
<Extension()>
Public Sub Save(ByVal msg As MailMessage, FileName As String)
Dim asm As Assembly = New SmtpClient().GetType().Assembly
Dim _mailWriterType As Type = asm.GetType("System.Net.Mail.MailWriter")
Using _fileStream As FileStream = New FileStream(FileName, FileMode.Create)
' Get reflection info for MailWriter contructor
Dim _mailWriterContructor As ConstructorInfo = _mailWriterType.GetConstructor(BindingFlags.Instance Or BindingFlags.NonPublic, Nothing, New Type() {GetType(Stream)}, Nothing)
' Construct MailWriter object with our FileStream
Dim _mailWriter As Object = _mailWriterContructor.Invoke(New Object() {_fileStream})
' Get reflection info for Send() method on MailMessage
Dim _sendMethod As MethodInfo = New MailMessage().GetType().GetMethod("Send", BindingFlags.Instance Or BindingFlags.NonPublic)
' Call method passing in MailWriter
_sendMethod.Invoke(msg, BindingFlags.Instance Or BindingFlags.NonPublic, Nothing, New Object() {_mailWriter, True, True}, Nothing)
' Finally get reflection info for Close() method on our MailWriter
Dim _closeMethod As MethodInfo = _mailWriter.GetType().GetMethod("Close", BindingFlags.Instance Or BindingFlags.NonPublic)
' Call close method
_closeMethod.Invoke(_mailWriter, BindingFlags.Instance Or BindingFlags.NonPublic, Nothing, New Object() {}, Nothing)
End Using
End Sub
End Module
You may observe that you need to create extensions as a module.
The System.Net.Mail.MailMessage is badly missing the option of saving the Message as a file. Though there is a workaournd by using the SpecifiedPickupDirectory option of the SmtpClient to write the mail message ot the specific folder. This option however doesn't have flexibility in naming the files. In a multi-threaded parallel execution environment, it is difficult to identify and rename the specific files post writing to disk. There ought to be a better solution to handle this problem.
Solution:
You can extend the MailMessage class and add a Save method yourself. The Send method of the SmtpClient creates and uses MailWriter object to write out the mail message and it uses fileMailWriter when the SpecificPickupDirectory is specified as the DeliveryMethod. Create your own MailWriter object using FileStream and invoke the internal Send method, passing your MailWriter object. Check out this Code Project Article for more details. The code samples given there are for the C# language. Just in case you need, given below the same code for the Extension in VB.NET.
Imports System
Imports System.Net.Mail
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.IO
Imports System.Reflection
Imports System.Runtime.CompilerServices
Module MailMessageExtension
<Extension()>
Public Sub Save(ByVal msg As MailMessage, FileName As String)
Dim asm As Assembly = New SmtpClient().GetType().Assembly
Dim _mailWriterType As Type = asm.GetType("System.Net.Mail.MailWriter")
Using _fileStream As FileStream = New FileStream(FileName, FileMode.Create)
' Get reflection info for MailWriter contructor
Dim _mailWriterContructor As ConstructorInfo = _mailWriterType.GetConstructor(BindingFlags.Instance Or BindingFlags.NonPublic, Nothing, New Type() {GetType(Stream)}, Nothing)
' Construct MailWriter object with our FileStream
Dim _mailWriter As Object = _mailWriterContructor.Invoke(New Object() {_fileStream})
' Get reflection info for Send() method on MailMessage
Dim _sendMethod As MethodInfo = New MailMessage().GetType().GetMethod("Send", BindingFlags.Instance Or BindingFlags.NonPublic)
' Call method passing in MailWriter
_sendMethod.Invoke(msg, BindingFlags.Instance Or BindingFlags.NonPublic, Nothing, New Object() {_mailWriter, True, True}, Nothing)
' Finally get reflection info for Close() method on our MailWriter
Dim _closeMethod As MethodInfo = _mailWriter.GetType().GetMethod("Close", BindingFlags.Instance Or BindingFlags.NonPublic)
' Call close method
_closeMethod.Invoke(_mailWriter, BindingFlags.Instance Or BindingFlags.NonPublic, Nothing, New Object() {}, Nothing)
End Using
End Sub
End Module
You may observe that you need to create extensions as a module.