Skip to content

Commit d79ad14

Browse files
NLog 5 compatible, all properties layoutable, Update MailKit (#137)
* NLog 5 compatible, Update MailKit * run tests with .NET 6 as .NET 5 is EOL * obsolete fix and cleanup * vm * layoutable * fix typos * update Microsoft.SourceLink.GitHub * icon and license * readme * replace with RenderLogEvent Co-authored-by: Julian Verdurmen <[email protected]>
1 parent 195ebe3 commit d79ad14

11 files changed

+132
-101
lines changed

README.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=nlog.mailkit&metric=bugs)](https://sonarcloud.io/summary/new_code?id=nlog.mailkit)
66
[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=nlog.mailkit&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=nlog.mailkit)
77

8-
9-
Alternative Mail target for [NLog](https://github.com/nlog/nlog) using MailKit. Compatible with .NET standard 2+
8+
Alternative Mail target for [NLog](https://github.com/nlog/nlog) using [MailKit](https://github.com/jstedfast/MailKit). Compatible with .NET standard 2+
109

1110
Including this package will replace the original mail target and has the
1211
same options as the original mail target, see [docs of the original mailTarget](https://github.com/NLog/NLog/wiki/Mail-Target)
@@ -26,7 +25,7 @@ This library is integration tested with the [SmtpServer NuGet package](https://w
2625
`Install-Package NLog.MailKit` or in your csproj:
2726

2827
```xml
29-
<PackageReference Include="NLog.MailKit" Version="4.*" />
28+
<PackageReference Include="NLog.MailKit" Version="5.*" />
3029
```
3130

3231
2) Add to your nlog.config:
@@ -43,9 +42,6 @@ and config options can be found here: https://github.com/NLog/NLog/wiki/Mail-Tar
4342
Use `skipCertificateValidation="true"` for prevent `AuthenticationException` if your remote certificate for smtpServer is invalid - not recommend!
4443

4544

46-
47-
48-
4945
### License
5046
BSD. License of MailKit is MIT
5147

azure-pipelines.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ trigger:
33
- master
44
pool:
55
name: Azure Pipelines
6-
vmImage: 'windows-2019'
6+
vmImage: 'windows-latest'
77
demands:
88
- msbuild
99
- visualstudio
@@ -13,14 +13,14 @@ variables:
1313
Solution: 'src/NLog.MailKit.sln'
1414
BuildPlatform: 'Any CPU'
1515
BuildConfiguration: 'Release'
16-
Version: '4.1.0'
16+
Version: '5.0.0'
1717
FullVersion: '$(Version).$(Build.BuildId)'
1818

1919
steps:
2020
- task: NuGetToolInstaller@0
21-
displayName: 'Use NuGet 5.x'
21+
displayName: 'Use NuGet 6.x'
2222
inputs:
23-
versionSpec: 5.x
23+
versionSpec: 6.x
2424

2525
- task: DotNetCoreCLI@2
2626
displayName: 'dotnet restore'

src/NLog.MailKit.sln.DotSettings

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
2+
<s:Boolean x:Key="/Default/UserDictionary/Words/=longdate/@EntryIndexedValue">True</s:Boolean>
3+
<s:Boolean x:Key="/Default/UserDictionary/Words/=machinename/@EntryIndexedValue">True</s:Boolean>
4+
<s:Boolean x:Key="/Default/UserDictionary/Words/=NTLM/@EntryIndexedValue">True</s:Boolean>
5+
<s:Boolean x:Key="/Default/UserDictionary/Words/=stringbuilder/@EntryIndexedValue">True</s:Boolean>
6+
<s:Boolean x:Key="/Default/UserDictionary/Words/=XOAUTH/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

src/NLog.MailKit/MailTarget.cs

Lines changed: 55 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright (c) 2004-2021 Jaroslaw Kowalski <[email protected]>, Kim Christensen, Julian Verdurmen
2+
// Copyright (c) 2004-2022 Jaroslaw Kowalski <[email protected]>, Kim Christensen, Julian Verdurmen
33
//
44
// All rights reserved.
55
//
@@ -34,6 +34,7 @@
3434
using System;
3535
using System.Collections.Generic;
3636
using System.ComponentModel;
37+
using System.Diagnostics.CodeAnalysis;
3738
using System.Text;
3839
using MailKit.Net.Smtp;
3940
using MailKit.Security;
@@ -80,8 +81,12 @@ namespace NLog.MailKit
8081
/// <code lang="C#" source="examples/targets/Configuration API/Mail/Buffered/Example.cs" />
8182
/// </example>
8283
[Target("Mail")]
84+
[SuppressMessage("ReSharper", "RedundantStringFormatCall")]
8385
public class MailTarget : TargetWithLayoutHeaderAndFooter
8486
{
87+
private static readonly Encoding DefaultEncoding = System.Text.Encoding.UTF8;
88+
private const SecureSocketOptions DefaultSecureSocketOption = SecureSocketOptions.StartTlsWhenAvailable;
89+
8590
private const string RequiredPropertyIsEmptyFormat = "After the processing of the MailTarget's '{0}' property it appears to be empty. The email message will not be sent.";
8691

8792
/// <summary>
@@ -94,10 +99,10 @@ public MailTarget()
9499
{
95100
Body = "${message}${newline}";
96101
Subject = "Message from NLog on ${machinename}";
97-
Encoding = Encoding.UTF8;
102+
Encoding = DefaultEncoding;
98103
SmtpPort = 25;
99104
SmtpAuthentication = SmtpAuthenticationMode.None;
100-
SecureSocketOption = SecureSocketOptions.StartTlsWhenAvailable;
105+
SecureSocketOption = DefaultSecureSocketOption;
101106
Timeout = 10000;
102107
}
103108

@@ -143,7 +148,8 @@ public MailTarget(string name) : this()
143148
/// </summary>
144149
/// <value>A value of <c>true</c> if new lines should be added; otherwise, <c>false</c>.</value>
145150
/// <docgen category='Layout Options' order='99' />
146-
public bool AddNewLines { get; set; }
151+
[DefaultValue(false)]
152+
public Layout<bool> AddNewLines { get; set; }
147153

148154
/// <summary>
149155
/// Gets or sets the mail subject.
@@ -170,14 +176,14 @@ public Layout Body
170176
/// </summary>
171177
/// <docgen category='Layout Options' order='20' />
172178
[DefaultValue("UTF8")]
173-
public Encoding Encoding { get; set; }
179+
public Layout<Encoding> Encoding { get; set; }
174180

175181
/// <summary>
176182
/// Gets or sets a value indicating whether to send message as HTML instead of plain text.
177183
/// </summary>
178184
/// <docgen category='Layout Options' order='11' />
179185
[DefaultValue(false)]
180-
public bool Html { get; set; }
186+
public Layout<bool> Html { get; set; }
181187

182188
/// <summary>
183189
/// Gets or sets SMTP Server to be used for sending.
@@ -190,16 +196,16 @@ public Layout Body
190196
/// </summary>
191197
/// <docgen category='SMTP Options' order='11' />
192198
[DefaultValue("None")]
193-
public SmtpAuthenticationMode SmtpAuthentication { get; set; }
199+
public Layout<SmtpAuthenticationMode> SmtpAuthentication { get; set; }
194200

195201
/// <summary>
196-
/// Gets or sets the username used to connect to SMTP server (used when SmtpAuthentication is set to "basic").
202+
/// Gets or sets the username used to connect to SMTP server (used when <see cref="SmtpAuthentication"/> is set to "basic").
197203
/// </summary>
198204
/// <docgen category='SMTP Options' order='12' />
199205
public Layout SmtpUserName { get; set; }
200206

201207
/// <summary>
202-
/// Gets or sets the password used to authenticate against SMTP server (used when SmtpAuthentication is set to "basic").
208+
/// Gets or sets the password used to authenticate against SMTP server (used when <see cref="SmtpAuthentication"/> is set to "basic").
203209
/// </summary>
204210
/// <docgen category='SMTP Options' order='13' />
205211
public Layout SmtpPassword { get; set; }
@@ -212,31 +218,31 @@ public Layout Body
212218
/// <docgen category='SMTP Options' order='14' />
213219
/// .
214220
[DefaultValue(false)]
215-
public bool EnableSsl { get; set; }
221+
public Layout<bool> EnableSsl { get; set; }
216222

217223
/// <summary>
218224
/// Provides a way of specifying the SSL and/or TLS encryption
219225
///
220226
/// If <see cref="EnableSsl" /> is <c>true</c>, then <see cref="SecureSocketOptions.SslOnConnect" /> will be used.
221227
/// </summary>
222-
[DefaultValue(SecureSocketOptions.StartTlsWhenAvailable)]
228+
[DefaultValue(DefaultSecureSocketOption)]
223229
[CLSCompliant(false)]
224-
public SecureSocketOptions SecureSocketOption { get; set; }
230+
public Layout<SecureSocketOptions> SecureSocketOption { get; set; }
225231

226232
/// <summary>
227233
/// Gets or sets the port number that SMTP Server is listening on.
228234
/// </summary>
229235
/// <docgen category='SMTP Options' order='15' />
230236
[DefaultValue(25)]
231-
public int SmtpPort { get; set; }
237+
public Layout<int> SmtpPort { get; set; }
232238

233239
/// <summary>
234240
/// Gets or sets a value indicating whether SmtpClient should ignore invalid certificate.
235241
/// </summary>
236242
/// <docgen category='SMTP Options' order='16' />
237243
/// .
238244
[DefaultValue(false)]
239-
public bool SkipCertificateValidation { get; set; }
245+
public Layout<bool> SkipCertificateValidation { get; set; }
240246

241247
/// <summary>
242248
/// Gets or sets the priority used for sending mails.
@@ -248,22 +254,22 @@ public Layout Body
248254
/// </summary>
249255
/// <remarks>Only happens when <see cref="Html" /> is set to true.</remarks>
250256
[DefaultValue(false)]
251-
public bool ReplaceNewlineWithBrTagInHtml { get; set; }
257+
public Layout<bool> ReplaceNewlineWithBrTagInHtml { get; set; }
252258

253259
/// <summary>
254260
/// Gets or sets a value indicating the SMTP client timeout.
255261
/// </summary>
256-
/// <remarks>Warning: zero is not infinit waiting</remarks>
262+
/// <remarks>Warning: zero is not infinite waiting</remarks>
257263
[DefaultValue(10000)]
258-
public int Timeout { get; set; }
264+
public Layout<int> Timeout { get; set; }
259265

260266
/// <summary>
261267
/// Renders the logging event message and adds it to the internal ArrayList of log messages.
262268
/// </summary>
263269
/// <param name="logEvent">The logging event.</param>
264270
protected override void Write(AsyncLogEventInfo logEvent)
265271
{
266-
Write((IList<AsyncLogEventInfo>)new[] { logEvent });
272+
Write(new[] { logEvent });
267273
}
268274

269275
/// <summary>
@@ -289,9 +295,10 @@ protected override void InitializeTarget()
289295
InternalLogger.Debug("Init mailtarget with mailkit");
290296
CheckRequiredParameters();
291297

292-
if (SmtpAuthentication == SmtpAuthenticationMode.Ntlm)
298+
var smtpAuthentication = RenderLogEvent(SmtpAuthentication, LogEventInfo.CreateNullEvent());
299+
if (smtpAuthentication == SmtpAuthenticationMode.Ntlm)
293300
{
294-
throw new NLogConfigurationException("Ntlm not yet supported");
301+
throw new NLogConfigurationException("NTLM not yet supported");
295302
}
296303

297304
base.InitializeTarget();
@@ -321,26 +328,29 @@ private void ProcessSingleMailMessage(IList<AsyncLogEventInfo> events)
321328
using (var client = new SmtpClient())
322329
{
323330
CheckRequiredParameters();
324-
client.Timeout = Timeout;
331+
client.Timeout = RenderLogEvent(Timeout, lastEvent);
325332

326333
var renderedHost = SmtpServer.Render(lastEvent);
327334
if (string.IsNullOrEmpty(renderedHost))
328335
{
329-
throw new NLogRuntimeException(RequiredPropertyIsEmptyFormat, nameof(SmtpServer));
336+
throw new NLogRuntimeException(string.Format(RequiredPropertyIsEmptyFormat, nameof(SmtpServer)));
330337
}
331338

332-
var secureSocketOptions = EnableSsl ? SecureSocketOptions.SslOnConnect : SecureSocketOption;
333-
InternalLogger.Debug("Sending mail to {0} using {1}:{2} (socket option={3})", message.To, renderedHost, SmtpPort, secureSocketOptions);
339+
var enableSsl = RenderLogEvent(EnableSsl, lastEvent);
340+
var secureSocketOptions = enableSsl ? SecureSocketOptions.SslOnConnect : RenderLogEvent(SecureSocketOption, lastEvent, DefaultSecureSocketOption);
341+
var smtpPort = RenderLogEvent(SmtpPort, lastEvent);
342+
InternalLogger.Debug("Sending mail to {0} using {1}:{2} (socket option={3})", message.To, renderedHost, smtpPort, secureSocketOptions);
334343
InternalLogger.Trace(" Subject: '{0}'", message.Subject);
335344
InternalLogger.Trace(" From: '{0}'", message.From);
336345

337-
if (SkipCertificateValidation)
346+
var skipCertificateValidation = RenderLogEvent(SkipCertificateValidation, lastEvent);
347+
if (skipCertificateValidation)
338348
{
339349
client.ServerCertificateValidationCallback += (s, cert, chain, sslPolicyErrors) => true;
340350
}
341351

342352

343-
client.Connect(renderedHost, SmtpPort, secureSocketOptions);
353+
client.Connect(renderedHost, smtpPort, secureSocketOptions);
344354
InternalLogger.Trace(" Connecting succesfull");
345355

346356
// Note: since we don't have an OAuth2 token, disable
@@ -349,7 +359,8 @@ private void ProcessSingleMailMessage(IList<AsyncLogEventInfo> events)
349359

350360
// Note: only needed if the SMTP server requires authentication
351361

352-
if (SmtpAuthentication == SmtpAuthenticationMode.Basic)
362+
var smtpAuthentication = RenderLogEvent(SmtpAuthentication, LogEventInfo.CreateNullEvent());
363+
if (smtpAuthentication == SmtpAuthenticationMode.Basic)
353364
{
354365
var userName = SmtpUserName?.Render(lastEvent);
355366
var password = SmtpPassword?.Render(lastEvent);
@@ -397,10 +408,11 @@ private void ProcessSingleMailMessage(IList<AsyncLogEventInfo> events)
397408
private StringBuilder CreateBodyBuffer(IEnumerable<AsyncLogEventInfo> events, LogEventInfo firstEvent, LogEventInfo lastEvent)
398409
{
399410
var bodyBuffer = new StringBuilder();
411+
var addNewLines = RenderLogEvent(AddNewLines, firstEvent, false);
400412
if (Header != null)
401413
{
402414
bodyBuffer.Append(Header.Render(firstEvent));
403-
if (AddNewLines)
415+
if (addNewLines)
404416
{
405417
bodyBuffer.Append("\n");
406418
}
@@ -409,7 +421,7 @@ private StringBuilder CreateBodyBuffer(IEnumerable<AsyncLogEventInfo> events, Lo
409421
foreach (var eventInfo in events)
410422
{
411423
bodyBuffer.Append(Layout.Render(eventInfo.LogEvent));
412-
if (AddNewLines)
424+
if (addNewLines)
413425
{
414426
bodyBuffer.Append("\n");
415427
}
@@ -418,7 +430,7 @@ private StringBuilder CreateBodyBuffer(IEnumerable<AsyncLogEventInfo> events, Lo
418430
if (Footer != null)
419431
{
420432
bodyBuffer.Append(Footer.Render(lastEvent));
421-
if (AddNewLines)
433+
if (addNewLines)
422434
{
423435
bodyBuffer.Append("\n");
424436
}
@@ -431,17 +443,17 @@ private void CheckRequiredParameters()
431443
{
432444
if (SmtpServer == null)
433445
{
434-
throw new NLogConfigurationException(RequiredPropertyIsEmptyFormat, nameof(SmtpServer));
446+
throw new NLogConfigurationException(string.Format(RequiredPropertyIsEmptyFormat, nameof(SmtpServer)));
435447
}
436448

437449
if (From == null)
438450
{
439-
throw new NLogConfigurationException(RequiredPropertyIsEmptyFormat, nameof(From));
451+
throw new NLogConfigurationException(string.Format(RequiredPropertyIsEmptyFormat, nameof(From)));
440452
}
441453
}
442454

443455
/// <summary>
444-
/// Create key for grouping. Needed for multiple events in one mailmessage
456+
/// Create key for grouping. Needed for multiple events in one mail message
445457
/// </summary>
446458
/// <param name="logEvent">event for rendering layouts </param>
447459
/// <returns>string to group on</returns>
@@ -456,7 +468,7 @@ private string GetSmtpSettingsKey(LogEventInfo logEvent)
456468
AppendLayout(sb, logEvent, SmtpServer);
457469
AppendLayout(sb, logEvent, SmtpPassword);
458470
AppendLayout(sb, logEvent, SmtpUserName);
459-
471+
460472
return sb.ToString();
461473
}
462474

@@ -476,7 +488,7 @@ private static void AppendLayout(StringBuilder sb, LogEventInfo logEvent, Layout
476488
}
477489

478490
/// <summary>
479-
/// Create the mailmessage with the addresses, properties and body.
491+
/// Create the mail message with the addresses, properties and body.
480492
/// </summary>
481493
private MimeMessage CreateMailMessage(LogEventInfo lastEvent, string body)
482494
{
@@ -486,7 +498,7 @@ private MimeMessage CreateMailMessage(LogEventInfo lastEvent, string body)
486498

487499
if (string.IsNullOrEmpty(renderedFrom))
488500
{
489-
throw new NLogRuntimeException(RequiredPropertyIsEmptyFormat, "From");
501+
throw new NLogRuntimeException(string.Format(RequiredPropertyIsEmptyFormat, "From"));
490502
}
491503

492504
msg.From.Add(MailboxAddress.Parse(renderedFrom));
@@ -497,13 +509,11 @@ private MimeMessage CreateMailMessage(LogEventInfo lastEvent, string body)
497509

498510
if (!addedTo && !addedCc && !addedBcc)
499511
{
500-
throw new NLogRuntimeException(RequiredPropertyIsEmptyFormat, "To/Cc/Bcc");
512+
throw new NLogRuntimeException(string.Format(RequiredPropertyIsEmptyFormat, "To/Cc/Bcc"));
501513
}
502514

503515
msg.Subject = Subject == null ? string.Empty : Subject.Render(lastEvent).Trim();
504516

505-
//todo msg.BodyEncoding = Encoding;
506-
507517
if (Priority != null)
508518
{
509519
var renderedPriority = Priority.Render(lastEvent);
@@ -513,15 +523,18 @@ private MimeMessage CreateMailMessage(LogEventInfo lastEvent, string body)
513523
TextPart CreateBodyPart()
514524
{
515525
var newBody = body;
516-
if (Html && ReplaceNewlineWithBrTagInHtml)
526+
var html = RenderLogEvent(Html, lastEvent);
527+
var replaceNewlineWithBrTagInHtml = RenderLogEvent(ReplaceNewlineWithBrTagInHtml, lastEvent);
528+
if (html && replaceNewlineWithBrTagInHtml)
517529
{
518530
newBody = newBody?.Replace(Environment.NewLine, "<br/>");
519531
}
520532

521-
return new TextPart(Html ? TextFormat.Html : TextFormat.Plain)
533+
var encoding = RenderLogEvent(Encoding, lastEvent, DefaultEncoding);
534+
return new TextPart(html ? TextFormat.Html : TextFormat.Plain)
522535
{
523536
Text = newBody,
524-
ContentType = { Charset = Encoding?.WebName }
537+
ContentType = { Charset = encoding?.WebName }
525538
};
526539
}
527540

src/NLog.MailKit/N.png

1.86 KB
Loading

0 commit comments

Comments
 (0)