@@ -245,6 +245,12 @@ public Layout Body
245245 /// <remarks>Warning: zero is not infinite waiting</remarks>
246246 public Layout < int > Timeout { get ; set ; } = 10000 ;
247247
248+ /// <summary>
249+ /// Gets or sets the folder where applications save mail messages to be processed by the local SMTP server.
250+ /// </summary>
251+ /// <docgen category='SMTP Options' order='17' />
252+ public Layout PickupDirectoryLocation { get ; set ; }
253+
248254 /// <summary>
249255 /// Gets the array of email headers that are transmitted with this email message
250256 /// </summary>
@@ -305,58 +311,20 @@ private void ProcessSingleMailMessage(IEnumerable<AsyncLogEventInfo> events)
305311
306312 var message = CreateMailMessage ( lastEvent , bodyBuffer . ToString ( ) ) ;
307313
308- using ( var client = new SmtpClient ( ) )
314+ var pickupFolder = RenderLogEvent ( PickupDirectoryLocation , lastEvent ) ;
315+ if ( ! string . IsNullOrEmpty ( pickupFolder ) )
309316 {
310- client . Timeout = RenderLogEvent ( Timeout , lastEvent ) ;
311-
312- var renderedHost = RenderLogEvent ( SmtpServer , lastEvent ) ;
313- if ( string . IsNullOrEmpty ( renderedHost ) )
314- {
315- throw new NLogRuntimeException ( string . Format ( RequiredPropertyIsEmptyFormat , nameof ( SmtpServer ) ) ) ;
316- }
317-
318- var enableSsl = RenderLogEvent ( EnableSsl , lastEvent ) ;
319- var secureSocketOptions = enableSsl ? SecureSocketOptions . SslOnConnect : RenderLogEvent ( SecureSocketOption , lastEvent , DefaultSecureSocketOption ) ;
320- var smtpPort = RenderLogEvent ( SmtpPort , lastEvent ) ;
321- InternalLogger . Debug ( "Sending mail to {0} using {1}:{2}" , message . To , renderedHost , smtpPort ) ;
322- InternalLogger . Trace ( " Subject: '{0}'" , message . Subject ) ;
323- InternalLogger . Trace ( " From: '{0}'" , message . From ) ;
324-
325- var skipCertificateValidation = RenderLogEvent ( SkipCertificateValidation , lastEvent ) ;
326- if ( skipCertificateValidation )
327- {
328- client . ServerCertificateValidationCallback += ( s , cert , chain , sslPolicyErrors ) => true ;
329- }
330-
331-
332- client . Connect ( renderedHost , smtpPort , secureSocketOptions ) ;
333- InternalLogger . Trace ( "{0}: Connecting succesfull" , this ) ;
334-
335- // Note: since we don't have an OAuth2 token, disable
336- // the XOAUTH2 authentication mechanism.
337- client . AuthenticationMechanisms . Remove ( "XOAUTH2" ) ;
338-
339- // Note: only needed if the SMTP server requires authentication
340-
341- var smtpAuthentication = RenderLogEvent ( SmtpAuthentication , lastEvent ) ;
342- if ( smtpAuthentication == SmtpAuthenticationMode . Basic )
343- {
344- var userName = RenderLogEvent ( SmtpUserName , lastEvent ) ;
345- var password = RenderLogEvent ( SmtpPassword , lastEvent ) ;
346-
347- InternalLogger . Trace ( "{0}: Authenticate with username '{1}'" , this , userName ) ;
348- client . Authenticate ( userName , password ) ;
349- }
350-
351- client . Send ( message ) ;
352- InternalLogger . Trace ( "{0}: Sending mail done. Disconnecting" , this ) ;
353- client . Disconnect ( true ) ;
354- InternalLogger . Trace ( "{0}: Disconnected" , this ) ;
355-
356- foreach ( var ev in events )
357- {
358- ev . Continuation ( null ) ;
359- }
317+ var emailFilePath = ResolvePickupDirectoryLocationFilePath ( pickupFolder ) ;
318+ message . WriteTo ( emailFilePath ) ;
319+ }
320+ else
321+ {
322+ SendMailMessage ( message , lastEvent ) ;
323+ }
324+
325+ foreach ( var ev in events )
326+ {
327+ ev . Continuation ( null ) ;
360328 }
361329 }
362330 catch ( Exception exception )
@@ -374,6 +342,57 @@ private void ProcessSingleMailMessage(IEnumerable<AsyncLogEventInfo> events)
374342 }
375343 }
376344
345+ private void SendMailMessage ( MimeMessage message , LogEventInfo lastEvent )
346+ {
347+ using ( var client = new SmtpClient ( ) )
348+ {
349+ client . Timeout = RenderLogEvent ( Timeout , lastEvent ) ;
350+
351+ var renderedHost = RenderLogEvent ( SmtpServer , lastEvent ) ;
352+ if ( string . IsNullOrEmpty ( renderedHost ) )
353+ {
354+ throw new NLogRuntimeException ( string . Format ( RequiredPropertyIsEmptyFormat , nameof ( SmtpServer ) ) ) ;
355+ }
356+
357+ var enableSsl = RenderLogEvent ( EnableSsl , lastEvent ) ;
358+ var secureSocketOptions = enableSsl ? SecureSocketOptions . SslOnConnect : RenderLogEvent ( SecureSocketOption , lastEvent , DefaultSecureSocketOption ) ;
359+ var smtpPort = RenderLogEvent ( SmtpPort , lastEvent ) ;
360+ InternalLogger . Debug ( "Sending mail to {0} using {1}:{2}" , message . To , renderedHost , smtpPort ) ;
361+ InternalLogger . Trace ( " Subject: '{0}'" , message . Subject ) ;
362+ InternalLogger . Trace ( " From: '{0}'" , message . From ) ;
363+
364+ var skipCertificateValidation = RenderLogEvent ( SkipCertificateValidation , lastEvent ) ;
365+ if ( skipCertificateValidation )
366+ {
367+ client . ServerCertificateValidationCallback += ( s , cert , chain , sslPolicyErrors ) => true ;
368+ }
369+
370+ client . Connect ( renderedHost , smtpPort , secureSocketOptions ) ;
371+ InternalLogger . Trace ( "{0}: Connecting succesfull" , this ) ;
372+
373+ // Note: since we don't have an OAuth2 token, disable
374+ // the XOAUTH2 authentication mechanism.
375+ client . AuthenticationMechanisms . Remove ( "XOAUTH2" ) ;
376+
377+ // Note: only needed if the SMTP server requires authentication
378+
379+ var smtpAuthentication = RenderLogEvent ( SmtpAuthentication , lastEvent ) ;
380+ if ( smtpAuthentication == SmtpAuthenticationMode . Basic )
381+ {
382+ var userName = RenderLogEvent ( SmtpUserName , lastEvent ) ;
383+ var password = RenderLogEvent ( SmtpPassword , lastEvent ) ;
384+
385+ InternalLogger . Trace ( "{0}: Authenticate with username '{1}'" , this , userName ) ;
386+ client . Authenticate ( userName , password ) ;
387+ }
388+
389+ client . Send ( message ) ;
390+ InternalLogger . Trace ( "{0}: Sending mail done. Disconnecting" , this ) ;
391+ client . Disconnect ( true ) ;
392+ InternalLogger . Trace ( "{0}: Disconnected" , this ) ;
393+ }
394+ }
395+
377396 /// <summary>
378397 /// Create buffer for body
379398 /// </summary>
@@ -414,6 +433,35 @@ private StringBuilder CreateBodyBuffer(IEnumerable<AsyncLogEventInfo> events, Lo
414433 return bodyBuffer ;
415434 }
416435
436+ /// <summary>
437+ /// Handle <paramref name="pickupDirectoryLocation"/> if it is a virtual directory.
438+ /// </summary>
439+ internal string ResolvePickupDirectoryLocationFilePath ( string pickupDirectoryLocation )
440+ {
441+ const string virtualPathPrefix = "~/" ;
442+
443+ if ( pickupDirectoryLocation . StartsWith ( virtualPathPrefix , StringComparison . Ordinal ) )
444+ {
445+ // Support for Virtual Paths
446+ var root = AppDomain . CurrentDomain . BaseDirectory ;
447+ var directory = pickupDirectoryLocation . Substring ( virtualPathPrefix . Length ) . Replace ( '/' , System . IO . Path . DirectorySeparatorChar ) ;
448+ pickupDirectoryLocation = System . IO . Path . Combine ( root , directory ) ;
449+ }
450+
451+ string filename ;
452+ string pathAndFilename ;
453+ while ( true )
454+ {
455+ filename = Guid . NewGuid ( ) . ToString ( ) + ".eml" ;
456+ pathAndFilename = System . IO . Path . Combine ( pickupDirectoryLocation , filename ) ;
457+ if ( ! System . IO . File . Exists ( pathAndFilename ) )
458+ break ;
459+ }
460+
461+ InternalLogger . Debug ( "{0}: Writing mail to file: {1}" , this , pathAndFilename ) ;
462+ return pathAndFilename ;
463+ }
464+
417465 private void CheckRequiredParameters ( )
418466 {
419467 var smtpAuthentication = RenderLogEvent ( SmtpAuthentication , LogEventInfo . CreateNullEvent ( ) ) ;
@@ -479,7 +527,7 @@ private MimeMessage CreateMailMessage(LogEventInfo lastEvent, string body)
479527 newBody = newBody ? . Replace ( Environment . NewLine , "<br/>" ) ;
480528 if ( newBody ? . IndexOf ( '\n ' ) >= 0 )
481529 {
482- newBody = newBody ? . Replace ( "\n " , "<br/>" ) ;
530+ newBody = newBody . Replace ( "\n " , "<br/>" ) ;
483531 }
484532 }
485533
0 commit comments