-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathMessages.cs
More file actions
1091 lines (970 loc) · 55.6 KB
/
Messages.cs
File metadata and controls
1091 lines (970 loc) · 55.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#region Related components
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Mail;
using System.Text;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
#if NETSTANDARD2_0
using System.Runtime.InteropServices;
#endif
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
#endregion
namespace net.vieapps.Components.Utility
{
/// <summary>
/// Presents an email message
/// </summary>
[DebuggerDisplay("Subject = {Subject}")]
public class EmailMessage
{
/// <summary>
/// Initializes a new email message
/// </summary>
public EmailMessage() : this(null) { }
/// <summary>
/// Initializes a new email message
/// </summary>
/// <param name="encryptedMessage">The encrypted message</param>
public EmailMessage(string encryptedMessage)
{
if (!string.IsNullOrWhiteSpace(encryptedMessage))
try
{
this.CopyFrom(encryptedMessage.Decrypt(EmailMessage.EncryptionKey).ToJson().As<EmailMessage>());
}
catch { }
}
#region Properties
public string From { get; set; } = "";
public string ReplyTo { get; set; }
public string To { get; set; } = "";
public string Cc { get; set; } = "";
public string Bcc { get; set; } = "";
public string Subject { get; set; } = "";
public string Body { get; set; } = "";
public string Footer { get; set; }
public string Attachment { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
public MailPriority Priority { get; set; } = MailPriority.Normal;
public bool IsBodyHtml { get; set; } = true;
public int Encoding { get; set; } = System.Text.Encoding.UTF8.CodePage;
public string SmtpServer { get; set; }
public int SmtpServerPort { get; set; } = 25;
public string SmtpUsername { get; set; }
public string SmtpPassword { get; set; }
public bool SmtpServerEnableSsl { get; set; } = true;
public string SmtpMailer { get; set; }
public string SmtpClientDomain { get; set; }
static string _EncryptionKey = null;
internal static string EncryptionKey => EmailMessage._EncryptionKey ?? (EmailMessage._EncryptionKey = UtilityService.GetAppSetting("Keys:Encryption", "VIEApps-9D17C42D-Core-AE9F-Components-4D72-Message-586D-Encryption-277D9E606F1F-Keys"));
/// <summary>
/// Gets or sets the identity of the message
/// </summary>
public string ID { get; set; } = UtilityService.NewUUID;
/// <summary>
/// Gets or sets the correlation identity of the message
/// </summary>
public string CorrelationID { get; set; } = UtilityService.NewUUID;
/// <summary>
/// Gets or sets time to start to send this message via email
/// </summary>
/// <remarks>
/// Set a specifict time to tell mailer send this message from this time
/// </remarks>
public DateTime SendingTime { get; set; } = DateTime.Now;
#endregion
#region Working with files
/// <summary>
/// Loads message from file and deserialize as object
/// </summary>
/// <param name="filePath">The full path to a file that contains the encrypted message</param>
/// <param name="cancellationToken">The cancellation token</param>
/// <returns></returns>
public static async Task<EmailMessage> LoadAsync(string filePath, CancellationToken cancellationToken = default)
=> !string.IsNullOrWhiteSpace(filePath) && File.Exists(filePath)
? new EmailMessage(await UtilityService.ReadAsTextAsync(filePath, cancellationToken).ConfigureAwait(false))
: null;
/// <summary>
/// Serializes and saves message into file
/// </summary>
/// <param name="message">The message</param>
/// <param name="directory">The path to a directory that stores the queue of messages</param>
/// <param name="cancellationToken">The cancellation token</param>
public static async Task SaveAsync(EmailMessage message, string directory, CancellationToken cancellationToken = default)
{
if (message != null && Directory.Exists(directory))
try
{
await message.Encrypted.SaveAsTextAsync(Path.Combine(directory, message.ID + ".msg"), cancellationToken).ConfigureAwait(false);
}
catch { }
}
#endregion
/// <summary>
/// Gets the JSON that presents the message
/// </summary>
[JsonIgnore]
public JToken AsJson => this.ToJson();
/// <summary>
/// Gets the string that presents the encrypted messages
/// </summary>
[JsonIgnore]
public string Encrypted => this.AsJson.ToString(Formatting.None).Encrypt(EmailMessage.EncryptionKey);
}
// ------------------------------------------------------------------------------------------------------
/// <summary>
/// Presents a web-hook message
/// </summary>
[DebuggerDisplay("Endpoint = {EndpointURL}")]
public class WebHookMessage
{
/// <summary>
/// Initializes a new web-hook message
/// </summary>
public WebHookMessage() : this(null) { }
/// <summary>
/// Initializes a new web-hook message
/// </summary>
/// <param name="encryptedMessage">The encrypted message</param>
public WebHookMessage(string encryptedMessage)
{
if (!string.IsNullOrWhiteSpace(encryptedMessage))
try
{
this.CopyFrom(encryptedMessage.Decrypt(WebHookMessage.EncryptionKey).ToJson().As<WebHookMessage>());
}
catch { }
}
#region Properties
/// <summary>
/// Gets or Sets the url of webhook's endpoint
/// </summary>
public string EndpointURL { get; set; } = "";
/// <summary>
/// Gets or Sets the body of the webhook message
/// </summary>
public string Body { get; set; } = "";
/// <summary>
/// Gets or Sets header of webhook message
/// </summary>
public Dictionary<string, string> Header { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
/// <summary>
/// Gets or Sets query-string of webhook message
/// </summary>
public Dictionary<string, string> Query { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
static string _EncryptionKey = null;
internal static string EncryptionKey => WebHookMessage._EncryptionKey ?? (WebHookMessage._EncryptionKey = UtilityService.GetAppSetting("Keys:Encryption", "VIEApps-9D17C42D-Core-AE9F-Components-4D72-Message-586D-Encryption-277D9E606F1F-Keys"));
/// <summary>
/// Gets or sets identity of the message
/// </summary>
public string ID { get; set; } = UtilityService.NewUUID;
/// <summary>
/// Gets or sets the correlation identity of the message
/// </summary>
public string CorrelationID { get; set; } = UtilityService.NewUUID;
/// <summary>
/// Gets or sets time to start to send this message
/// </summary>
public DateTime SendingTime { get; set; } = DateTime.Now;
#endregion
#region Working with files
/// <summary>
/// Loads message from file and deserialize as object
/// </summary>
/// <param name="filePath">The full path to a file that contains the encrypted message</param>
/// <param name="cancellationToken">The cancellation token</param>
/// <returns></returns>
public static async Task<WebHookMessage> LoadAsync(string filePath, CancellationToken cancellationToken = default)
=> !string.IsNullOrWhiteSpace(filePath) && File.Exists(filePath)
? new WebHookMessage(await UtilityService.ReadAsTextAsync(filePath, cancellationToken).ConfigureAwait(false))
: null;
/// <summary>
/// Serializes and saves message into file
/// </summary>
/// <param name="message">The message</param>
/// <param name="directory">The path to a directory that stores the queue of messages</param>
/// <param name="cancellationToken">The cancellation token</param>
public static async Task SaveAsync(WebHookMessage message, string directory, CancellationToken cancellationToken = default)
{
if (message != null && Directory.Exists(directory))
try
{
await message.Encrypted.SaveAsTextAsync(Path.Combine(directory, message.ID + ".msg"), cancellationToken).ConfigureAwait(false);
}
catch { }
}
#endregion
/// <summary>
/// Gets the JSON that presents the message
/// </summary>
[JsonIgnore]
public JToken AsJson => this.ToJson(json => json["Body"] = (this.Body ?? "").ToJSON());
/// <summary>
/// Gets the string that presents the encrypted messages
/// </summary>
[JsonIgnore]
public string Encrypted => this.ToJson().ToString(Formatting.None).Encrypt(WebHookMessage.EncryptionKey);
}
// ------------------------------------------------------------------------------------------------------
/// <summary>
/// Collection of global methods for sending a message (email and web hook)
/// </summary>
public static partial class MessageService
{
#region Working with a email message
/// <summary>
/// Gets the collection of harmful domains need to prevent while sending email messages
/// </summary>
public static HashSet<string> HarmfulDomains { get; } = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
/// <summary>
/// Prepares a valid email address
/// </summary>
/// <param name="emailAddress">The string that presents information of an email adress before validating</param>
/// <param name="convertNameToANSI">true to convert display name as ANSI</param>
/// <returns><see cref="System.Net.Mail.MailAddress">MailAddress</see> object that contains valid email address</returns>
public static MailAddress GetMailAddress(this string emailAddress, bool convertNameToANSI = false)
{
if (string.IsNullOrWhiteSpace(emailAddress))
return null;
string email, displayName = "";
var emails = emailAddress.ToArray('<');
if (emails.Length > 1)
{
email = emails[1];
displayName = emails[0];
if (convertNameToANSI)
displayName = displayName.ConvertUnicodeToANSI();
}
else
email = emails[0];
email = email.Replace("<", "").Replace(">", "").Replace(" ", "").ToLower().Trim();
while (email.StartsWith("/") || email.StartsWith(@"\"))
email = email.Right(email.Length - 1);
return email.Equals("")
? null
: new MailAddress(email, displayName, Encoding.UTF8);
}
/// <summary>
/// Gets the domain name from the email address
/// </summary>
/// <param name="emailAddress"></param>
/// <returns></returns>
public static string GetDomain(this string emailAddress)
{
var domain = "";
if (!string.IsNullOrWhiteSpace(emailAddress))
{
var pos = emailAddress.PositionOf("@");
if (pos > 0)
domain = emailAddress.Right(emailAddress.Length - pos - 1);
if (emailAddress.EndsWith(">"))
domain = emailAddress.Right(emailAddress.Length - 1);
}
return domain.ToLower();
}
/// <summary>
/// Gets an e-mail message
/// </summary>
/// <param name="fromAddress">Sender address</param>
/// <param name="replyToAddress">Address will be replied to</param>
/// <param name="toAddresses">Collection of recipients</param>
/// <param name="ccAddresses">Collection of CC recipients</param>
/// <param name="bccAddresses">Collection of BCC recipients</param>
/// <param name="subject">The message subject</param>
/// <param name="body">The message body</param>
/// <param name="attachments">Collection of attachment files (means the collection of files with full path)</param>
/// <param name="footer">The additional footer (will be placed at the bottom of the body)</param>
/// <param name="priority">The priority</param>
/// <param name="isBodyHtml">true if the message body is HTML formated</param>
/// <param name="encoding">Encoding of subject and body message</param>
/// <param name="mailer">The name of mailer agent (means 'x-mailer' header)</param>
public static MailMessage GetMailMessage(MailAddress fromAddress, MailAddress replyToAddress, IEnumerable<MailAddress> toAddresses, IEnumerable<MailAddress> ccAddresses, IEnumerable<MailAddress> bccAddresses, string subject, string body, IEnumerable<string> attachments, string footer = null, MailPriority priority = MailPriority.Normal, bool isBodyHtml = true, Encoding encoding = null, string mailer = null)
{
// check
if (string.IsNullOrWhiteSpace(subject) || string.IsNullOrWhiteSpace(body))
throw new MessageException("The email must have subject and body");
if (fromAddress == null || string.IsNullOrWhiteSpace(fromAddress.Address))
throw new MessageException("The email must have sender address");
if ((toAddresses == null || !toAddresses.Any()) && (ccAddresses == null || !ccAddresses.Any()) && (bccAddresses == null || !bccAddresses.Any()))
throw new MessageException("The email must have at least one recipient");
// create new mail message
var message = new MailMessage
{
From = new MailAddress(fromAddress.Address, fromAddress.DisplayName.ConvertUnicodeToANSI(), encoding ?? Encoding.UTF8),
Priority = priority,
Subject = subject.Trim(),
SubjectEncoding = encoding ?? Encoding.UTF8,
Body = $"{body.Trim()}{footer ?? ""}",
BodyEncoding = encoding ?? Encoding.UTF8,
IsBodyHtml = isBodyHtml
};
// reply to
if (replyToAddress != null)
message.ReplyToList.Add(replyToAddress);
// recipients
toAddresses?.Where(emailAddress => emailAddress != null).ForEach(emailAddress => message.To.Add(emailAddress));
ccAddresses?.Where(emailAddress => emailAddress != null).ForEach(emailAddress => message.CC.Add(emailAddress));
bccAddresses?.Where(emailAddress => emailAddress != null).ForEach(emailAddress => message.Bcc.Add(emailAddress));
// attachments
attachments?.Where(attachment => File.Exists(attachment)).ForEach(attachment => message.Attachments.Add(new Attachment(attachment)));
// final
message.Headers.Add("x-mailer", mailer ?? "vieapps.ngx");
return message;
}
/// <summary>
/// Gets an e-mail message
/// </summary>
/// <param name="from">Sender name and e-mail address</param>
/// <param name="replyTo">Address will be replied to</param>
/// <param name="to">Recipients, seperated multiple by semi-colon (;)</param>
/// <param name="cc">CC recipients, seperated multiple by semi-colon (;)</param>
/// <param name="bcc">BCC recipients, seperated multiple by semi-colon (;)</param>
/// <param name="subject">The message subject</param>
/// <param name="body">The message body</param>
/// <param name="attachment">The full path to an attachment file</param>
/// <param name="footer">The additional footer (will be placed at the bottom of the body)</param>
/// <param name="priority">The priority</param>
/// <param name="isBodyHtml">true if the message body is HTML formated</param>
/// <param name="encoding">Encoding of subject and body message</param>
/// <param name="mailer">The name of mailer agent (means 'x-mailer' header)</param>
public static MailMessage GetMailMessage(string from, string replyTo, string to, string cc, string bcc, string subject, string body, string attachment, string footer = null, MailPriority priority = MailPriority.Normal, bool isBodyHtml = true, Encoding encoding = null, string mailer = null)
{
// check & validate
if (from.Equals(""))
throw new MessageException("No sender information for the message");
var toEmails = string.IsNullOrWhiteSpace(to)
? ""
: to.Trim();
var ccEmails = string.IsNullOrWhiteSpace(cc)
? ""
: cc.Trim();
var bccEmails = string.IsNullOrWhiteSpace(bcc)
? ""
: bcc.Trim();
if (toEmails.Equals("") && ccEmails.Equals("") && bccEmails.Equals(""))
throw new MessageException("No recipient for the message");
// prepare
MailAddress fromAddress = null;
try
{
fromAddress = from.ConvertUnicodeToANSI().GetMailAddress();
}
catch
{
fromAddress = UtilityService.GetAppSetting("Email:DefaultSender", "VIEApps NGX <vieapps.net@gmail.com>").GetMailAddress();
}
MailAddress replyToAddress = null;
if (!string.IsNullOrWhiteSpace(replyTo))
try
{
replyToAddress = replyTo.GetMailAddress();
}
catch { }
var toAddresses = string.IsNullOrWhiteSpace(toEmails)
? null
: toEmails.ToArray(';', true, true).Select(email =>
{
try
{
return email.GetMailAddress();
}
catch
{
return null;
}
});
var ccAddresses = string.IsNullOrWhiteSpace(toEmails)
? null
: ccEmails.ToArray(';', true, true).Select(email =>
{
try
{
return email.GetMailAddress();
}
catch
{
return null;
}
});
var bccAddresses = string.IsNullOrWhiteSpace(toEmails)
? null
: bccEmails.ToArray(';', true, true).Select(email =>
{
try
{
return email.GetMailAddress();
}
catch
{
return null;
}
});
// get the mail message
return MessageService.GetMailMessage(fromAddress, replyToAddress, toAddresses, ccAddresses, bccAddresses, subject, body, new[] { attachment }, footer, priority, isBodyHtml, encoding, mailer);
}
/// <summary>
/// Normalizes the email message
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public static MailMessage Normalize(this MailMessage message)
{
if (message == null)
throw new MessageException();
if (MessageService.HarmfulDomains.Count > 0)
{
if (message.To != null && message.To.Count > 0)
{
var index = 0;
while (index < message.To.Count)
{
if (MessageService.HarmfulDomains.Contains(message.To[index].Address.GetDomain()))
message.To.RemoveAt(index);
else
index++;
}
}
if (message.CC != null && message.CC.Count > 0)
{
var index = 0;
while (index < message.CC.Count)
{
if (MessageService.HarmfulDomains.Contains(message.CC[index].Address.GetDomain()))
message.CC.RemoveAt(index);
else
index++;
}
}
if (message.Bcc != null && message.Bcc.Count > 0)
{
var index = 0;
while (index < message.Bcc.Count)
{
if (MessageService.HarmfulDomains.Contains(message.Bcc[index].Address.GetDomain()))
message.Bcc.RemoveAt(index);
else
index++;
}
}
}
if ((message.To == null || message.To.Count < 1)
&& (message.CC == null || message.CC.Count < 1)
&& (message.Bcc == null || message.Bcc.Count < 1))
throw new MessageException("The message must have at least one recipient");
return message;
}
#endregion
#region Working with a SMTP client
/// <summary>
/// Gets the Smtp client for sending email messages
/// </summary>
/// <param name="host">The host address of the SMTP server (IP or host name)</param>
/// <param name="port">The port number of SMTP service on the SMTP server</param>
/// <param name="user">The name of user for connecting with SMTP server</param>
/// <param name="password">The password of user for connecting with SMTP server</param>
/// <param name="enableSsl">true if the SMTP server requires SSL</param>
/// <param name="clientDomain">Domain for the client (replacement of computer name)</param>
public static SmtpClient GetSmtpClient(string host, int port, string user, string password, bool enableSsl, string clientDomain = null)
{
var smtp = new SmtpClient
{
Host = host ?? "127.0.0.1",
Port = port,
EnableSsl = enableSsl,
DeliveryMethod = SmtpDeliveryMethod.Network
};
// credential
if (!string.IsNullOrWhiteSpace(user) && !string.IsNullOrWhiteSpace(password))
smtp.Credentials = new NetworkCredential(user, password);
#if NETSTANDARD2_0
// service point - only available on Windows with .NET Framework
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && RuntimeInformation.FrameworkDescription.IsContains(".NET Framework"))
smtp.ServicePoint.Expect100Continue = false;
#endif
// client domain
typeof(SmtpClient).GetField("clientDomain", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(smtp, clientDomain ?? "vieapps.ngx");
return smtp;
}
/// <summary>
/// Gets the SMTP client for sending email messages
/// </summary>
/// <param name="host">The host address of the SMTP server (IP or host name)</param>
/// <param name="port">The port number of SMTP service on the SMTP server</param>
/// <param name="user">The name of user for connecting with SMTP server</param>
/// <param name="password">The password of user for connecting with SMTP server</param>
/// <param name="enableSsl">true if the SMTP server requires SSL</param>
/// <param name="clientDomain">Domain for the client (replacement of computer name)</param>
public static SmtpClient GetSmtpClient(string host, string port, string user, string password, bool enableSsl, string clientDomain = null)
{
enableSsl = !string.IsNullOrWhiteSpace(host) ? enableSsl : "true".IsEquals(UtilityService.GetAppSetting("Email:SmtpServerEnableSsl"));
host = !string.IsNullOrWhiteSpace(host) ? host : UtilityService.GetAppSetting("Email:SmtpServer");
port = !string.IsNullOrWhiteSpace(port) ? port : UtilityService.GetAppSetting("Email:SmtpPort");
user = !string.IsNullOrWhiteSpace(user) ? user : UtilityService.GetAppSetting("Email:SmtpUser");
password = !string.IsNullOrWhiteSpace(password) ? password : UtilityService.GetAppSetting("Email:SmtpUserPassword");
return MessageService.GetSmtpClient(host, Int32.TryParse(port, out var smtpPort) && smtpPort > 0 ? smtpPort : 25, user, password, enableSsl, clientDomain);
}
#endregion
#region Send email messages
/// <summary>
/// Sends an email message using a SMTP client
/// </summary>
/// <param name="smtp">The SMTP client for sending email</param>
/// <param name="message">The email message</param>
public static void SendMail(this SmtpClient smtp, MailMessage message)
{
// check
if (smtp == null)
throw new MessageException("The SMTP client is invalid");
if (message == null)
throw new MessageException("The message is invalid");
// send
smtp.Send(message.Normalize());
}
/// <summary>
/// Sends an email message using a SMTP client
/// </summary>
/// <param name="smtp">The SMTP client for sending email</param>
/// <param name="message">The email message</param>
/// <param name="cancellationToken">The cancellation token</param>
public static Task SendMailAsync(this SmtpClient smtp, MailMessage message, CancellationToken cancellationToken)
=> smtp == null
? Task.FromException(new MessageException("The SMTP client is invalid"))
: message == null
? Task.FromException(new MessageException("The message is invalid"))
#if NETSTANDARD2_0
: smtp.SendMailAsync(message.Normalize()).WithCancellationToken(cancellationToken);
#else
: smtp.SendMailAsync(message.Normalize(), cancellationToken);
#endif
/// <summary>
/// Sends an email message using a SMTP client
/// </summary>
/// <param name="smtp">The SMTP client for sending email</param>
/// <param name="fromAddress">Sender address</param>
/// <param name="replyToAddress">Address will be replied to</param>
/// <param name="toAddresses">Collection of recipients</param>
/// <param name="ccAddresses">Collection of CC recipients</param>
/// <param name="bccAddresses">Collection of BCC recipients</param>
/// <param name="subject">The message subject</param>
/// <param name="body">The message body</param>
/// <param name="attachments">Collection of attachment files (means the collection of files with full path)</param>
/// <param name="footer">The additional footer (will be placed at the bottom of the body)</param>
/// <param name="priority">The priority</param>
/// <param name="isBodyHtml">true if the message body is HTML formated</param>
/// <param name="encoding">Encoding of subject and body message</param>
/// <param name="mailer">The name of mailer agent (means 'x-mailer' header)</param>
public static void SendMail(this SmtpClient smtp, MailAddress fromAddress, MailAddress replyToAddress, IEnumerable<MailAddress> toAddresses, IEnumerable<MailAddress> ccAddresses, IEnumerable<MailAddress> bccAddresses, string subject, string body, IEnumerable<string> attachments, string footer = null, MailPriority priority = MailPriority.Normal, bool isBodyHtml = true, Encoding encoding = null, string mailer = null)
{
if (smtp == null)
throw new MessageException("The SMTP client is invalid");
smtp.SendMail(MessageService.GetMailMessage(fromAddress, replyToAddress, toAddresses, ccAddresses, bccAddresses, subject, body, attachments, footer, priority, isBodyHtml, encoding, mailer));
}
/// <summary>
/// Sends an email message using a SMTP client
/// </summary>
/// <param name="smtp">The SMTP client for sending email</param>
/// <param name="fromAddress">Sender address</param>
/// <param name="replyToAddress">Address will be replied to</param>
/// <param name="toAddresses">Collection of recipients</param>
/// <param name="ccAddresses">Collection of CC recipients</param>
/// <param name="bccAddresses">Collection of BCC recipients</param>
/// <param name="subject">The message subject</param>
/// <param name="body">The message body</param>
/// <param name="attachments">Collection of attachment files (means the collection of files with full path)</param>
/// <param name="footer">The additional footer (will be placed at the bottom of the body)</param>
/// <param name="priority">The priority</param>
/// <param name="isHtmlFormat">true if the message body is HTML formated</param>
/// <param name="encoding">Encoding of subject and body message</param>
/// <param name="mailer">The name of mailer agent (means 'x-mailer' header)</param>
/// <param name="cancellationToken">The cancellation token</param>
public static Task SendMailAsync(this SmtpClient smtp, MailAddress fromAddress, MailAddress replyToAddress, IEnumerable<MailAddress> toAddresses, IEnumerable<MailAddress> ccAddresses, IEnumerable<MailAddress> bccAddresses, string subject, string body, IEnumerable<string> attachments, string footer = null, MailPriority priority = MailPriority.Normal, bool isHtmlFormat = true, Encoding encoding = null, string mailer = null, CancellationToken cancellationToken = default)
=> smtp == null
? Task.FromException(new MessageException("The SMTP client is invalid"))
: smtp.SendMailAsync(MessageService.GetMailMessage(fromAddress, replyToAddress, toAddresses, ccAddresses, bccAddresses, subject, body, attachments, footer, priority, isHtmlFormat, encoding, mailer), cancellationToken);
/// <summary>
/// Sends an email message using the default SMTP client
/// </summary>
/// <param name="fromAddress">Sender address</param>
/// <param name="replyToAddress">Address will be replied to</param>
/// <param name="toAddresses">Collection of recipients</param>
/// <param name="ccAddresses">Collection of CC recipients</param>
/// <param name="bccAddresses">Collection of BCC recipients</param>
/// <param name="subject">The message subject</param>
/// <param name="body">The message body</param>
/// <param name="attachments">Collection of attachment files (means the collection of files with full path)</param>
/// <param name="footer">The additional footer (will be placed at the bottom of the body)</param>
/// <param name="priority">The priority</param>
/// <param name="isBodyHtml">true if the message body is HTML formated</param>
/// <param name="encoding">Encoding of subject and body message</param>
/// <param name="mailer">The name of mailer agent (means 'x-mailer' header)</param>
/// <param name="smtpServerHost">The host address of the SMTP server (IP or host name)</param>
/// <param name="smtpServerPort">The port number of SMTP service on the SMTP server</param>
/// <param name="smtpServerUser">The name of user for connecting with SMTP server</param>
/// <param name="smtpServerPassword">The password of user for connecting with SMTP server</param>
/// <param name="smtpServerEnableSsl">true if the SMTP server requires SSL</param>
/// <param name="smtpClientDomain">The host name of mailer client</param>
public static void SendMail(MailAddress fromAddress, MailAddress replyToAddress, IEnumerable<MailAddress> toAddresses, IEnumerable<MailAddress> ccAddresses, IEnumerable<MailAddress> bccAddresses, string subject, string body, IEnumerable<string> attachments, string footer = null, MailPriority priority = MailPriority.Normal, bool isBodyHtml = true, Encoding encoding = null, string mailer = null, string smtpServerHost = null, string smtpServerPort = null, string smtpServerUser = null, string smtpServerPassword = null, bool smtpServerEnableSsl = true, string smtpClientDomain = null)
{
using (var smtp = MessageService.GetSmtpClient(smtpServerHost, smtpServerPort, smtpServerUser, smtpServerPassword, smtpServerEnableSsl, smtpClientDomain))
smtp.SendMail(fromAddress, replyToAddress, toAddresses, ccAddresses, bccAddresses, subject, body, attachments, footer, priority, isBodyHtml, encoding, mailer);
}
/// <summary>
/// Sends an email message using the default SMTP client
/// </summary>
/// <param name="fromAddress">Sender address</param>
/// <param name="replyToAddress">Address will be replied to</param>
/// <param name="toAddresses">Collection of recipients</param>
/// <param name="ccAddresses">Collection of CC recipients</param>
/// <param name="bccAddresses">Collection of BCC recipients</param>
/// <param name="subject">The message subject</param>
/// <param name="body">The message body</param>
/// <param name="attachments">Collection of attachment files (means the collection of files with full path)</param>
/// <param name="footer">The additional footer (will be placed at the bottom of the body)</param>
/// <param name="priority">The priority</param>
/// <param name="isBodyHtml">true if the message body is HTML formated</param>
/// <param name="encoding">Encoding of subject and body message</param>
/// <param name="mailer">The name of mailer agent (means 'x-mailer' header)</param>
/// <param name="smtpServerHost">The host address of the SMTP server (IP or host name)</param>
/// <param name="smtpServerPort">The port number of SMTP service on the SMTP server</param>
/// <param name="smtpServerUser">The name of user for connecting with SMTP server</param>
/// <param name="smtpServerPassword">The password of user for connecting with SMTP server</param>
/// <param name="smtpServerEnableSsl">true if the SMTP server requires SSL</param>
/// <param name="smtpClientDomain">The host name of mailer client</param>
/// <param name="cancellationToken">The cancellation token</param>
public static async Task SendMailAsync(MailAddress fromAddress, MailAddress replyToAddress, IEnumerable<MailAddress> toAddresses, IEnumerable<MailAddress> ccAddresses, IEnumerable<MailAddress> bccAddresses, string subject, string body, IEnumerable<string> attachments, string footer = null, MailPriority priority = MailPriority.Normal, bool isBodyHtml = true, Encoding encoding = null, string mailer = null, string smtpServerHost = null, string smtpServerPort = null, string smtpServerUser = null, string smtpServerPassword = null, bool smtpServerEnableSsl = true, string smtpClientDomain = null, CancellationToken cancellationToken = default)
{
using (var smtp = MessageService.GetSmtpClient(smtpServerHost, smtpServerPort, smtpServerUser, smtpServerPassword, smtpServerEnableSsl, smtpClientDomain))
await smtp.SendMailAsync(fromAddress, replyToAddress, toAddresses, ccAddresses, bccAddresses, subject, body, attachments, footer, priority, isBodyHtml, encoding, mailer, cancellationToken).ConfigureAwait(false);
}
/// <summary>
/// Sends an email message using a SMTP client
/// </summary>
/// <param name="smtp">The SMTP client for sending email</param>
/// <param name="from">Sender name and e-mail address</param>
/// <param name="replyTo">Address will be replied to</param>
/// <param name="to">Recipients, seperated multiple by semi-colon (;)</param>
/// <param name="cc">CC recipients, seperated multiple by semi-colon (;)</param>
/// <param name="bcc">BCC recipients, seperated multiple by semi-colon (;)</param>
/// <param name="subject">The message subject</param>
/// <param name="body">The message body</param>
/// <param name="attachment">The full path to an attachment file</param>
/// <param name="footer">The additional footer (will be placed at the bottom of the body)</param>
/// <param name="priority">The priority</param>
/// <param name="isBodyHtml">true if the message body is HTML formated</param>
/// <param name="encoding">Encoding of subject and body message</param>
/// <param name="mailer">The name of mailer agent (means 'x-mailer' header)</param>
public static void SendMail(this SmtpClient smtp, string from, string replyTo, string to, string cc, string bcc, string subject, string body, string attachment, string footer = null, MailPriority priority = MailPriority.Normal, bool isBodyHtml = true, Encoding encoding = null, string mailer = null)
{
if (smtp == null)
throw new MessageException("The SMTP client is invalid");
smtp.SendMail(MessageService.GetMailMessage(from, replyTo, to, cc, bcc, subject, body, attachment, footer, priority, isBodyHtml, encoding, mailer));
}
/// <summary>
/// Sends an email message using a SMTP client
/// </summary>
/// <param name="smtp">The SMTP client for sending email</param>
/// <param name="from">Sender name and e-mail address</param>
/// <param name="replyTo">Address will be replied to</param>
/// <param name="to">Recipients, seperated multiple by semi-colon (;)</param>
/// <param name="cc">CC recipients, seperated multiple by semi-colon (;)</param>
/// <param name="bcc">BCC recipients, seperated multiple by semi-colon (;)</param>
/// <param name="subject">The message subject</param>
/// <param name="body">The message body</param>
/// <param name="attachment">The full path to an attachment file</param>
/// <param name="footer">The additional footer (will be placed at the bottom of the body)</param>
/// <param name="priority">The priority</param>
/// <param name="isBodyHtml">true if the message body is HTML formated</param>
/// <param name="encoding">Encoding of subject and body message</param>
/// <param name="mailer">The name of mailer agent (means 'x-mailer' header)</param>
/// <param name="cancellationToken">The cancellation token</param>
public static Task SendMailAsync(this SmtpClient smtp, string from, string replyTo, string to, string cc, string bcc, string subject, string body, string attachment, string footer = null, MailPriority priority = MailPriority.Normal, bool isBodyHtml = true, Encoding encoding = null, string mailer = null, CancellationToken cancellationToken = default)
=> smtp == null
? Task.FromException(new MessageException("The SMTP client is invalid"))
: smtp.SendMailAsync(MessageService.GetMailMessage(from, replyTo, to, cc, bcc, subject, body, attachment, footer, priority, isBodyHtml, encoding, mailer), cancellationToken);
/// <summary>
/// Sends an email message using the default SMTP client
/// </summary>
/// <param name="from">Sender name and e-mail address</param>
/// <param name="replyTo">Address will be replied to</param>
/// <param name="to">Recipients, seperated multiple by semi-colon (;)</param>
/// <param name="cc">CC recipients, seperated multiple by semi-colon (;)</param>
/// <param name="bcc">BCC recipients, seperated multiple by semi-colon (;)</param>
/// <param name="subject">The message subject</param>
/// <param name="body">The message body</param>
/// <param name="attachment">The full path to an attachment file</param>
/// <param name="footer">The additional footer (will be placed at the bottom of the body)</param>
/// <param name="priority">The priority</param>
/// <param name="isBodyHtml">true if the message body is HTML formated</param>
/// <param name="encoding">Encoding of subject and body message</param>
/// <param name="mailer">The name of mailer agent (means 'x-mailer' header)</param>
/// <param name="smtpServerHost">The host address of the SMTP server (IP or host name)</param>
/// <param name="smtpServerPort">The port number of SMTP service on the SMTP server</param>
/// <param name="smtpServerUser">The name of user for connecting with SMTP server</param>
/// <param name="smtpServerPassword">The password of user for connecting with SMTP server</param>
/// <param name="smtpServerEnableSsl">true if the SMTP server requires SSL</param>
/// <param name="smtpClientDomain">The host name of mailer client</param>
public static void SendMail(string from, string replyTo, string to, string cc, string bcc, string subject, string body, string attachment, string footer = null, MailPriority priority = MailPriority.Normal, bool isBodyHtml = true, Encoding encoding = null, string mailer = null, string smtpServerHost = null, string smtpServerPort = null, string smtpServerUser = null, string smtpServerPassword = null, bool smtpServerEnableSsl = true, string smtpClientDomain = null)
{
using (var smtp = MessageService.GetSmtpClient(smtpServerHost, smtpServerPort, smtpServerUser, smtpServerPassword, smtpServerEnableSsl, smtpClientDomain))
smtp.SendMail(from, replyTo, to, cc, bcc, subject, body, attachment, footer, priority, isBodyHtml, encoding, mailer);
}
/// <summary>
/// Sends an email message using the default SMTP client
/// </summary>
/// <param name="from">Sender name and e-mail address</param>
/// <param name="replyTo">Address will be replied to</param>
/// <param name="to">Recipients, seperated multiple by semi-colon (;)</param>
/// <param name="cc">CC recipients, seperated multiple by semi-colon (;)</param>
/// <param name="bcc">BCC recipients, seperated multiple by semi-colon (;)</param>
/// <param name="subject">The message subject</param>
/// <param name="body">The message body</param>
/// <param name="attachment">The full path to an attachment file</param>
/// <param name="footer">The additional footer (will be placed at the bottom of the body)</param>
/// <param name="priority">The priority</param>
/// <param name="isBodyHtml">true if the message body is HTML formated</param>
/// <param name="encoding">Encoding of subject and body message</param>
/// <param name="mailer">The name of mailer agent (means 'x-mailer' header)</param>
/// <param name="smtpServerHost">The host address of the SMTP server (IP or host name)</param>
/// <param name="smtpServerPort">The port number of SMTP service on the SMTP server</param>
/// <param name="smtpServerUser">The name of user for connecting with SMTP server</param>
/// <param name="smtpServerPassword">The password of user for connecting with SMTP server</param>
/// <param name="smtpServerEnableSsl">true if the SMTP server requires SSL</param>
/// <param name="smtpClientDomain">The host name of mailer client</param>
/// <param name="cancellationToken">The cancellation token</param>
public static async Task SendMailAsync(string from, string replyTo, string to, string cc, string bcc, string subject, string body, string attachment, string footer = null, MailPriority priority = MailPriority.Normal, bool isBodyHtml = true, Encoding encoding = null, string mailer = null, string smtpServerHost = null, string smtpServerPort = null, string smtpServerUser = null, string smtpServerPassword = null, bool smtpServerEnableSsl = true, string smtpClientDomain = null, CancellationToken cancellationToken = default)
{
using (var smtp = MessageService.GetSmtpClient(smtpServerHost, smtpServerPort, smtpServerUser, smtpServerPassword, smtpServerEnableSsl, smtpClientDomain))
await smtp.SendMailAsync(from, replyTo, to, cc, bcc, subject, body, attachment, footer, priority, isBodyHtml, encoding, mailer, cancellationToken).ConfigureAwait(false);
}
/// <summary>
/// Sends the collection of email messages using a SMTP client
/// </summary>
/// <param name="smtp">The SMTP client for sending email</param>
/// <param name="messages">The collection of email messages</param>
public static void SendMails(this SmtpClient smtp, IEnumerable<MailMessage> messages)
{
if (smtp == null)
throw new MessageException("The SMTP client is invalid");
messages?.Where(message => message != null).ForEach(message => smtp.Send(message.Normalize()));
}
/// <summary>
/// Sends the collection of email messages using a SMTP client
/// </summary>
/// <param name="smtp"></param>
/// <param name="messages"></param>
/// <param name="cancellationToken">The cancellation token</param>
public static Task SendMailsAsync(this SmtpClient smtp, IEnumerable<MailMessage> messages, CancellationToken cancellationToken = default)
=> smtp == null
? Task.FromException(new MessageException("The SMTP client is invalid"))
: messages == null
? Task.CompletedTask
: messages.Where(message => message != null).ForEachAsync((message, token) => smtp.SendMailAsync(message, token), cancellationToken);
/// <summary>
/// Sends this email message
/// </summary>
/// <param name="message">The email message</param>
public static void Send(this EmailMessage message)
{
if (message == null)
throw new MessageException("The message is invalid");
MessageService.SendMail(message.From, message.ReplyTo, message.To, message.Cc, message.Bcc, message.Subject, message.Body, message.Attachment, message.Footer, message.Priority, message.IsBodyHtml, Encoding.GetEncoding(message.Encoding), message.SmtpMailer, message.SmtpServer, message.SmtpServerPort.ToString(), message.SmtpUsername, message.SmtpPassword, message.SmtpServerEnableSsl, message.SmtpClientDomain);
}
/// <summary>
/// Sends this email message
/// </summary>
/// <param name="message">The email message</param>
/// <param name="cancellationToken">The cancellation token</param>
public static Task SendAsync(this EmailMessage message, CancellationToken cancellationToken = default)
=> message == null
? Task.FromException(new MessageException("The message is invalid"))
: MessageService.SendMailAsync(message.From, message.ReplyTo, message.To, message.Cc, message.Bcc, message.Subject, message.Body, message.Attachment, message.Footer, message.Priority, message.IsBodyHtml, Encoding.GetEncoding(message.Encoding), message.SmtpMailer, message.SmtpServer, message.SmtpServerPort.ToString(), message.SmtpUsername, message.SmtpPassword, message.SmtpServerEnableSsl, message.SmtpClientDomain, cancellationToken);
#endregion
#region Send webhook messages
/// <summary>
/// Normalizes the web-hook message
/// </summary>
/// <param name="message">The web-hook message</param>
/// <param name="secretToken">The value of secret token (replacement of signature)</param>
/// <param name="secretTokenName">The name of secret token (in header or query string), default is 'x-webhook-secret-token'</param>
/// <param name="signAlgorithm">The HMAC algorithm to sign with the body by a specified key (md5, sha1, sha256, sha384, sha512, ripemd/ripemd160, blake128, blake/blake256, blake384, blake512)</param>
/// <param name="signKey">The key that use to sign</param>
/// <param name="signKeyIsHex">true to use bytes of hex-string sign-key</param>
/// <param name="signatureName">The name of the signature parameter, default is combination of algorithm and the string 'Signature', ex: HmacSha256Signature</param>
/// <param name="signatureAsHex">true to use signature as hex, false to use as Base64</param>
/// <param name="signatureInQuery">true to place the signature in query string, false to place in header, default is false</param>
/// <param name="signaturePrefix">The additional prefix of the signature</param>
/// <param name="signatureSuffix">The additional suffix of the signature</param>
/// <param name="signWithTimestamp">true to sign with Unix timestamp (place before raw body)</param>
/// <param name="signWithTimestampName">The name of the timestamp parameter, default is 'x-webhook-timestamp'</param>
/// <param name="signWithTimestampConnect">The value to connect between timestamp and raw body, default is dot (.)</param>
/// <param name="additionalQuery">The additional query string</param>
/// <param name="additionalHeader">The additional header</param>
/// <param name="encryptionKey">The AES key (256 bits-length) for encrypting message's body</param>
/// <param name="encryptionIV">The AES initialize vector (128 bits-length) for encrypting message's body</param>
/// <returns></returns>
public static WebHookMessage Normalize(this WebHookMessage message, string secretToken, string secretTokenName, string signAlgorithm, string signKey, bool signKeyIsHex, string signatureName, bool signatureAsHex, bool signatureInQuery, string signaturePrefix, string signatureSuffix, bool signWithTimestamp, string signWithTimestampName, string signWithTimestampConnect, IDictionary<string, string> additionalQuery, IDictionary<string, string> additionalHeader, byte[] encryptionKey, byte[] encryptionIV)
{
if (message == null)
throw new MessageException();
if (string.IsNullOrWhiteSpace(message.EndpointURL) || string.IsNullOrWhiteSpace(message.Body))
throw new MessageException("Invalid (end-point/body)");
message.Query = new Dictionary<string, string>(message.Query ?? new Dictionary<string, string>(), StringComparer.OrdinalIgnoreCase);
additionalQuery?.ForEach(kvp => message.Query[kvp.Key] = kvp.Value);
message.Header = new Dictionary<string, string>(message.Header ?? new Dictionary<string, string>(), StringComparer.OrdinalIgnoreCase);
additionalHeader?.ForEach(kvp => message.Header[kvp.Key] = kvp.Value);
if (!string.IsNullOrWhiteSpace(secretToken))
message.Header[string.IsNullOrWhiteSpace(secretTokenName) ? "x-webhook-secret-token" : secretTokenName] = secretToken;
var timestamp = DateTime.Now.ToUnixTimestamp().ToString();
if (signWithTimestamp)
{
signWithTimestampName = string.IsNullOrWhiteSpace(signWithTimestampName) ? "x-webhook-timestamp" : signWithTimestampName;
if (signatureInQuery)
message.Query[signWithTimestampName] = timestamp;
else
message.Header[signWithTimestampName] = timestamp;
}
try
{
message.Body = encryptionKey != null && encryptionKey.Length > 0 && encryptionIV != null && encryptionIV.Length > 0
? message.Body.ToBytes().Encrypt(encryptionKey, encryptionIV).ToBase64()
: message.Body;
}
catch (Exception ex)
{
throw new MessageException("Cannot encrypt", ex);
}
signAlgorithm = string.IsNullOrWhiteSpace(signAlgorithm) || !CryptoService.HmacHashAlgorithmFactories.ContainsKey(signAlgorithm) ? "SHA256" : signAlgorithm;
signatureName = string.IsNullOrWhiteSpace(signatureName) ? $"x-webhook-signature-hmac-{signAlgorithm.ToLower()}" : signatureName;
signKeyIsHex = signKeyIsHex && !string.IsNullOrWhiteSpace(signKey);
signKey = string.IsNullOrWhiteSpace(signKey) ? CryptoService.DEFAULT_PASS_PHRASE : signKey;
using (var signer = CryptoService.GetHMACHashAlgorithm(signKeyIsHex ? signKey.HexToBytes() : signKey.ToBytes(), signAlgorithm))
{
signWithTimestampConnect = string.IsNullOrWhiteSpace(signWithTimestampConnect) ? "." : signWithTimestampConnect;
var body = ((signWithTimestamp ? timestamp + signWithTimestampConnect : "") + message.Body).ToBytes();
var signature = signatureAsHex ? signer.ComputeHash(body).ToHex() : signer.ComputeHash(body).ToBase64();
if (signatureInQuery)
message.Query[signatureName] = $"{signaturePrefix ?? ""}{signature}{signatureSuffix ?? ""}";
else
message.Header[signatureName] = $"{signaturePrefix ?? ""}{signature}{signatureSuffix ?? ""}";
}
return message;
}
/// <summary>
/// Validates the web-hook message
/// </summary>
/// <param name="message">The web-hook message</param>
/// <param name="secretToken">The value of secret token (replacement of signature)</param>
/// <param name="secretTokenName">The name of secret token (in header or query string)</param>
/// <param name="signAlgorithm">The HMAC algorithm to sign with the body by a specified key (md5, sha1, sha256, sha384, sha512, ripemd/ripemd160, blake128, blake/blake256, blake384, blake512)</param>
/// <param name="signKey">The key that use to sign</param>
/// <param name="signKeyIsHex">true to use bytes of hex-string sign-key</param>
/// <param name="signatureName">The name of the signature parameter, default is combination of algorithm and the string 'Signature', ex: HmacSha256Signature</param>
/// <param name="signatureAsHex">true to use signature as hex, false to use as Base64</param>
/// <param name="signaturePrefix">The additional prefix of the signature</param>
/// <param name="signatureSuffix">The additional suffix of the signature</param>
/// <param name="signWithTimestamp">true to sign with Unix timestamp (place before raw body)</param>
/// <param name="signWithTimestampName">The name of the timestamp parameter, default is 'x-webhook-timestamp'</param>
/// <param name="signWithTimestampConnect">The value to connect between timestamp and raw body, default is dot (.)</param>
/// <param name="requiredQuery">The required query string parameters</param>
/// <param name="requiredHeader">The required header parameters</param>
/// <param name="decryptionKey">The AES key (256 bits-length) for decrypting message's body</param>
/// <param name="decryptionIV">The AES initialize vector (128 bits-length) for decrypting message's body</param>
/// <returns></returns>
public static WebHookMessage Validate(this WebHookMessage message, string secretToken, string secretTokenName, string signAlgorithm, string signKey, bool signKeyIsHex, string signatureName, bool signatureAsHex, string signaturePrefix, string signatureSuffix, bool signWithTimestamp, string signWithTimestampName, string signWithTimestampConnect, IDictionary<string, string> requiredQuery, IDictionary<string, string> requiredHeader, byte[] decryptionKey, byte[] decryptionIV)
{
if (message == null)
throw new MessageException();
if (decryptionKey != null && decryptionKey.Length > 0 && decryptionIV != null && decryptionIV.Length > 0)
try
{