public EmailMessageData( string subject, string plainTextBody, string htmlBody, string sender, IReadOnlyList <string> to, IReadOnlyList <string> cc, IReadOnlyList <string> bcc, IReadOnlyList <string> replyTo, Guid messageTrackingId, int deliveryCount) { if (messageTrackingId == Guid.Empty) { throw new ArgumentOutOfRangeException(nameof(messageTrackingId)); } MessageTrackingId = messageTrackingId; DeliveryCount = deliveryCount; Sender = sender ?? throw new ArgumentNullException(nameof(sender)); PlainTextBody = plainTextBody ?? throw new ArgumentNullException(nameof(plainTextBody)); HtmlBody = htmlBody ?? throw new ArgumentNullException(nameof(htmlBody)); Subject = subject ?? throw new ArgumentNullException(nameof(subject)); To = to ?? throw new ArgumentNullException(nameof(to)); if (!To.Any()) { throw new ArgumentOutOfRangeException(nameof(to), "At least 1 value should be defined for this argument."); } CC = cc ?? new List <string>(); Bcc = bcc ?? new List <string>(); ReplyTo = replyTo ?? new List <string>(); }
public SmtpEmailMessage(string from, IEnumerable <string> to, string subject, string body) { if (string.IsNullOrWhiteSpace(from)) { throw new InvalidOperationException("Missing 'From' name/address for smtp mail message"); } if (to == null) { throw new InvalidOperationException("Missing 'To' specification for smtp mail message"); } To = to.ToList(); if (!To.Any()) { throw new InvalidOperationException("Missing 'To' specification for smtp mail message"); } if (string.IsNullOrWhiteSpace(subject)) { throw new InvalidOperationException("Missing 'Subject' for smtp mail message"); } if (string.IsNullOrWhiteSpace(body)) { throw new InvalidOperationException("Missing 'Body' for smtp mail message"); } From = from; Subject = subject; Body = body; }
public IEnumerable <ValidationResult> Validate(ValidationContext validationContext) { if (!(To?.Any() ?? false)) { yield return(new ValidationResult("At least one recipient must be supplied", new string[] { nameof(To) })); } IEnumerable <string> invalid; if (!ValidationUtils.AreAllValidEmailAddresses(To, out invalid)) { yield return(new ValidationResult("Not all 'To' email addresses are valid: " + string.Join(", ", invalid), new string[] { nameof(To) })); } if (!ValidationUtils.AreAllValidEmailAddresses(CC, out invalid)) { yield return(new ValidationResult("Not all 'CC' email addresses are valid: " + string.Join(", ", invalid), new string[] { nameof(To) })); } if (!ValidationUtils.AreAllValidEmailAddresses(To, out invalid)) { yield return(new ValidationResult("Not all 'Bcc' email addresses are valid: " + string.Join(", ", invalid), new string[] { nameof(To) })); } if (!Template.HasValue && string.IsNullOrWhiteSpace(Body)) { yield return(new ValidationResult("If no template was supplied, then body text is required", new string[] { nameof(Body) })); } }
public IEnumerable <ValidationResult> Validate(ValidationContext validationContext) { if (To == null || !To.Any()) { yield return(new ValidationResult("Invalid value for To", new[] { "To" })); } if (Body == null || Body.Content.IsNullOrEmpty()) { yield return(new ValidationResult("Invalid value for Body", new[] { "Body" })); } if (From == null || From.Address.IsNullOrEmpty()) { yield return(new ValidationResult("Invalid value for From", new[] { "From" })); } if (Type != NotificationMessageType.Sms || To == null) { yield break; } foreach (var to in To) { if (to.Address == null || !to.Address.StartsWith("+", StringComparison.InvariantCultureIgnoreCase)) { yield return(new ValidationResult( "Invalid value for To that should start with + and E.164 format.", new[] { "To" })); } } }
/// <summary> /// Validate email message /// </summary> /// <param name="isSchedule"></param> internal void Validate(bool isSchedule = false) { if (string.IsNullOrEmpty(Subject)) { throw new ArgumentNullException(nameof(Subject)); } if (string.IsNullOrEmpty(Body)) { throw new ArgumentNullException(nameof(Body)); } if (string.IsNullOrEmpty(From)) { throw new ArgumentNullException(nameof(From)); } if (To?.Any() != true) { throw new ArgumentNullException(nameof(To)); } if (!string.IsNullOrEmpty(SubjectEncoding) && Encoding.GetEncoding(SubjectEncoding) == null) { throw new ArgumentException($"Argument {nameof(SubjectEncoding)} has unsupported value {SubjectEncoding}"); } if (!string.IsNullOrEmpty(BodyEncoding) && Encoding.GetEncoding(BodyEncoding) == null) { throw new ArgumentException($"Argument {nameof(BodyEncoding)} has unsupported value {BodyEncoding}"); } if (isSchedule) { if (string.IsNullOrEmpty(Key)) { throw new ArgumentNullException(nameof(Key)); } if (!ScheduledFor.HasValue) { throw new ArgumentNullException(nameof(ScheduledFor)); } } var mailMessage = (MailMessage)this; }
public void Validate() { if (string.IsNullOrWhiteSpace(Subject)) throw new InvalidParametersException("Invalid subject"); if (string.IsNullOrWhiteSpace(Body)) throw new InvalidParametersException("Invalid body"); if (From == null) throw new InvalidParametersException("Invalid from"); if (To.Any(x => x == null)) throw new InvalidParametersException("Invalid TO address"); if (CC.Any(x => x == null)) throw new InvalidParametersException("Invalid CC address"); }
public MailMessage Build() { MailMessage mailMessage = new MailMessage(); if (From == null || string.IsNullOrWhiteSpace(From.Address)) { throw new ArgumentException(nameof(From)); } else { mailMessage.From = From; } if (To != null && To.Any()) { mailMessage.To.AddRange(To); } if (CC != null && CC.Any()) { mailMessage.CC.AddRange(CC); } if (Bcc != null && Bcc.Any()) { mailMessage.Bcc.AddRange(Bcc); } if (!string.IsNullOrWhiteSpace(Subject)) { mailMessage.Subject = Subject; } if (!string.IsNullOrWhiteSpace(Body)) { mailMessage.Body = Body; mailMessage.IsBodyHtml = IsBodyHtml; } if (Attachments != null && Attachments.Any()) { mailMessage.Attachments.AddRange(Attachments); } return(mailMessage); }
private void Validate() { if (string.IsNullOrEmpty(Subject)) { throw new ArgumentNullException(nameof(EmailService), "El campo Subject es requerido"); } if (string.IsNullOrEmpty(Body)) { throw new ArgumentNullException(nameof(EmailService), "El campo Body es requerido"); } if (!To.Any()) { throw new ArgumentNullException(nameof(EmailService), "El campo To al menos requiere un destinatario"); } }
public void Validate() { if (this.Settings == null) { throw new Exception("Settings must be supplied"); } this.Settings.Validate(); this.CleanCollections(); if (To?.Any() == false && CC?.Any() == false && BCC?.Any() == false) { throw new Exception("At lest one To, CC or BCC must be supplied"); } if (string.IsNullOrWhiteSpace(this.Body)) { throw new Exception("Body must have some content"); } if (string.IsNullOrWhiteSpace(this.Subject)) { throw new Exception("Subjet must be supplied"); } this.Sender?.Validate(); this.From?.Validate(); this.To?.Validate(); this.CC?.Validate(); this.BCC?.Validate(); this.ReplyToList?.Validate(); this.Headers?.Validate(); this.Attachments?.Validate(); if (this.Attachments?.Sum(s => s.Content.Length) > MAXIMUM_SUM_ATTACHMENTS_SIZE) { throw new Exception($"Total size of attachments exceeds {(20971520 / 1024) / 1024}MB"); } if (Headers?.Count > 0 && Headers.Select(s => s.Name.Trim()).Distinct(StringComparer.OrdinalIgnoreCase).Count() != Headers.Count) { throw new Exception("Duplicate email headers are not allowed"); } }
private void _validate() { if (string.IsNullOrEmpty(Subject)) { throw new ArgumentNullException("", "El campo Subject es requerido"); } if (string.IsNullOrEmpty(Body)) { throw new ArgumentNullException("", "El campo Body es requerido"); } if (!To.Any()) { throw new ArgumentNullException("", "El campo To al menos requiere un destinatario"); } if (From is null) { From = new MailAddress(_configuration["Email:DefaultFrom"]); } }
public IEnumerable <ValidationResult> Validate(ValidationContext validationContext) { var validationResults = new List <ValidationResult>(); foreach (string email in To) { ValidateEmail(validationResults, email, nameof(To), "To"); } foreach (string email in CC) { ValidateEmail(validationResults, email, nameof(CC), "CC"); } foreach (string email in Bcc) { ValidateEmail(validationResults, email, nameof(Bcc), "BCC"); } if (!To.Any() && !CC.Any() && !Bcc.Any()) { validationResults.Add(new ValidationResult("This email doesn't define a recipient.", new[] { nameof(To) })); } return(validationResults); }
private string CheckIntegrity() { var message = new StringBuilder(); if (string.IsNullOrEmpty(From)) { message.AppendLine("No sender email address found."); } if (!To.Any()) { message.AppendLine("No destination email address found."); } if (string.IsNullOrEmpty(Subject)) { message.AppendLine("No subject found."); } if (string.IsNullOrEmpty(Body)) { message.AppendLine("No email body found."); } message.Append(CheckAttachments()); return(message.ToString()); }
public async System.Threading.Tasks.Task <System.Net.HttpStatusCode> SendAsync() { if (System.String.IsNullOrWhiteSpace(this.APIKeyPassword)) { return(System.Net.HttpStatusCode.Unauthorized); } if ((this.From == null) || (System.String.IsNullOrWhiteSpace(this.From.Address)) || (this.To == null) || (!(To.Any())) || (To.Any(i => System.String.IsNullOrWhiteSpace(i.Address)))) { return(System.Net.HttpStatusCode.BadRequest); } SendGrid.SendGridClient Client = new SendGrid.SendGridClient(this.APIKeyPassword); SendGrid.Helpers.Mail.EmailAddress FromEmailAddress = new SendGrid.Helpers.Mail.EmailAddress(this.From.Address, this.From.Name); SendGrid.Helpers.Mail.SendGridMessage Message; if (this.To.Count == 1) { Message = SendGrid.Helpers.Mail.MailHelper.CreateSingleEmail(FromEmailAddress, new SendGrid.Helpers.Mail.EmailAddress(this.To[0].Address, this.To[0].Name), this.Subject, this.PlainTextContent, this.HTMLContent); } else { Message = SendGrid.Helpers.Mail.MailHelper.CreateSingleEmailToMultipleRecipients(FromEmailAddress, To.Select(i => new SendGrid.Helpers.Mail.EmailAddress(i.Address, i.Name)).ToList(), this.Subject, this.PlainTextContent, this.HTMLContent); } return((await Client.SendEmailAsync(Message)).StatusCode); }
/// <summary> /// Encode this and all nested e-mail body parts. /// </summary> internal AbstractEMailBuilder EncodeBodyparts() { var SignTheMail = false; var EncryptTheMail = false; EMailBodypart BodypartToBeSecured = null; #region Add attachments, if available... if (_Attachments == null || _Attachments.Count == 0) { BodypartToBeSecured = _EncodeBodyparts(); } else { BodypartToBeSecured = new EMailBodypart(ContentTypeBuilder: AEMail => new MailContentType(AEMail, MailContentTypes.multipart_mixed) { CharSet = "utf-8" }.GenerateMIMEBoundary(), ContentTransferEncoding: "8bit", Content: new String[] { "This is a multi-part message in MIME format." }, NestedBodyparts: new EMailBodypart[] { _EncodeBodyparts() }. Concat(_Attachments)); } #endregion #region Check security settings switch (SecurityLevel) { case EMailSecurity.autosign: if (From.SecretKeyRing != null && From.SecretKeyRing.Any() && Passphrase.IsNotNullOrEmpty()) { SignTheMail = true; } break; case EMailSecurity.sign: if (From.SecretKeyRing == null || !From.SecretKeyRing.Any() || Passphrase.IsNullOrEmpty()) { throw new ApplicationException("Can not sign the e-mail!"); } SignTheMail = true; break; case EMailSecurity.auto: if (From.SecretKeyRing != null && From.SecretKeyRing.Any() && Passphrase.IsNotNullOrEmpty()) { SignTheMail = true; } if (SignTheMail && (!To.Any() | To.Any(v => v.PublicKeyRing != null && v.PublicKeyRing.Any())) && (!Cc.Any() | Cc.Any(v => v.PublicKeyRing != null && v.PublicKeyRing.Any()))) { EncryptTheMail = true; } break; case EMailSecurity.encrypt: if (From.SecretKeyRing == null || !From.SecretKeyRing.Any() || Passphrase.IsNullOrEmpty() || To.Any(v => v.PublicKeyRing == null || !v.PublicKeyRing.Any()) || Cc.Any(v => v.PublicKeyRing == null || !v.PublicKeyRing.Any())) { throw new ApplicationException("Can not sign and encrypt the e-mail!"); } EncryptTheMail = true; break; } #endregion #region Sign the e-mail if (SignTheMail & !EncryptTheMail) { var DataToBeSigned = BodypartToBeSecured. // Include headers of this MIME body // https://tools.ietf.org/html/rfc1847 Security Multiparts for MIME: ToText(). // Any trailing whitespace MUST then be removed from the signed material Select(line => line.TrimEnd()). // Canonical text format with <CR><LF> line endings // https://tools.ietf.org/html/rfc3156 5. OpenPGP signed data Aggregate((a, b) => a + "\r\n" + b) //ToDo: Apply Content-Transfer-Encoding ; // MIME Security with OpenPGP (rfc3156, https://tools.ietf.org/html/rfc3156) // OpenPGP Message Format (rfc4880, https://tools.ietf.org/html/rfc4880) _Body = new EMailBodypart(ContentTypeBuilder: AMail => new MailContentType(AMail, MailContentTypes.multipart_signed) { MicAlg = "pgp-sha512", Protocol = "application/pgp-signature", CharSet = "utf-8", }, ContentTransferEncoding: "8bit", NestedBodyparts: new EMailBodypart[] { BodypartToBeSecured, new EMailBodypart(ContentTypeBuilder: AMail => new MailContentType(AMail, MailContentTypes.application_pgp__signature) { CharSet = "utf-8" }, // ContentTransferEncoding: "8bit", ContentDescription: "OpenPGP digital signature", ContentDisposition: ContentDispositions.attachment.ToString() + "; filename=\"signature.asc\"", Content: new String[] { OpenPGP.CreateSignature(new MemoryStream(DataToBeSigned.ToUTF8Bytes()), From.SecretKeyRing.First(), Passphrase, HashAlgorithm: HashAlgorithm). WriteTo(new MemoryStream(), CloseOutputStream: false). ToUTF8String() }) } ); } #endregion #region Encrypt the e-mail else if (SignTheMail & EncryptTheMail) { var Plaintext = BodypartToBeSecured.ToText().Aggregate((a, b) => a + "\r\n" + b).ToUTF8Bytes(); var Ciphertext = new MemoryStream(); OpenPGP.EncryptSignAndZip(InputStream: new MemoryStream(Plaintext), Length: (UInt64)Plaintext.Length, SecretKey: From.SecretKeyRing.First(), Passphrase: Passphrase, PublicKey: To.First().PublicKeyRing.First(), OutputStream: Ciphertext, SymmetricKeyAlgorithm: SymmetricKeyAlgorithm, HashAlgorithm: HashAlgorithm, CompressionAlgorithm: CompressionAlgorithm, ArmoredOutput: true, Filename: "encrypted.asc", LastModificationTime: DateTime.UtcNow); // MIME Security with OpenPGP (rfc3156, https://tools.ietf.org/html/rfc3156) // OpenPGP Message Format (rfc4880, https://tools.ietf.org/html/rfc4880) _Body = new EMailBodypart(ContentTypeBuilder: AMail => new MailContentType(AMail, MailContentTypes.multipart_encrypted) { Protocol = "application/pgp-encrypted", CharSet = "utf-8", }, ContentTransferEncoding: "8bit", NestedBodyparts: new EMailBodypart[] { new EMailBodypart(ContentTypeBuilder: AMail => new MailContentType(AMail, MailContentTypes.application_pgp__encrypted) { CharSet = "utf-8" }, ContentDescription: "PGP/MIME version identification", ContentDisposition: ContentDispositions.attachment.ToString() + "; filename=\"signature.asc\"", Content: new String[] { "Version: 1" }), new EMailBodypart(ContentTypeBuilder: AMail => new MailContentType(AMail, MailContentTypes.application_octet__stream) { CharSet = "utf-8" }, ContentDescription: "OpenPGP encrypted message", ContentDisposition: ContentDispositions.inline.ToString() + "; filename=\"encrypted.asc\"", Content: new String[] { Ciphertext.ToArray().ToUTF8String() }), } ); } #endregion else { this._Body = BodypartToBeSecured; } return(this); }
public override string ToString() { StringBuilder sb = new StringBuilder(); string boundary = Guid.NewGuid().ToString(); var date = DateTime.Now.ToString("ddd, d MMM yyyy H:m:s zz00"); var subject = !Equals(SubjectEncoding, Encoding.ASCII) ? EncodeQuotedPrintableHeader(Subject, SubjectEncoding) : Subject; AddHeader(sb, "From", FormatMailAddress(From, HeaderEncoding)); if (To.Any()) { AddHeader(sb, "To", String.Join(", ", To.Select(t => FormatMailAddress(t, HeaderEncoding)))); } if (Cc.Any()) { AddHeader(sb, "Cc", String.Join(", ", Cc.Select(t => FormatMailAddress(t, HeaderEncoding)))); } AddHeader(sb, "Subject", subject); AddHeader(sb, "MIME-Version", "1.0"); AddHeader(sb, "Date", date); AddHeader(sb, "Message-ID", MessageId); foreach (var additionalHeader in AdditionalHeaders) { AddHeader(additionalHeader.Name, additionalHeader.Value); } if (Attachments.Any()) { AddHeader(sb, "Content-Type", "multipart/mixed; boundary=" + boundary); AddLine(sb, ""); AddLine(sb, "--" + boundary); } string boundary2 = Guid.NewGuid().ToString(); AddHeader(sb, "Content-Type", "multipart/alternative; boundary=" + boundary2); AddLine(sb, ""); AddLine(sb, "--" + boundary2); AddHeader(sb, "Content-Type", "text/plain; charset=" + BodyEncoding.HeaderName); AddHeader(sb, "Content-Transfer-Encoding", "quoted-printable"); AddHeader(sb, "Content-Disposition", "inline"); AddLine(sb, ""); AddLine(sb, encodeQuotedPrintable(Text, BodyEncoding)); AddLine(sb, "--" + boundary2); AddHeader(sb, "Content-Type", "text/html; charset=" + BodyEncoding.HeaderName); AddHeader(sb, "Content-Transfer-Encoding", "quoted-printable"); AddHeader(sb, "Content-Disposition", "inline"); AddLine(sb, ""); AddLine(sb, encodeQuotedPrintable(Html, BodyEncoding)); AddLine(sb, "--" + boundary2 + "--"); if (Attachments.Any()) { AddLine(sb, ""); foreach (var attachment in Attachments) { AddLine(sb, "--" + boundary); if (attachment.Encoding != null) { AddHeader(sb, "Content-Type", attachment.Type + "; charset=" + attachment.Encoding.HeaderName); } else { AddHeader(sb, "Content-Type", attachment.Type); } AddHeader(sb, "Content-Transfer-Encoding", "base64"); AddHeader(sb, "Content-Disposition", "attachment; filename=" + attachment.Name); AddLine(sb, ""); AddLine(sb, Convert.ToBase64String(attachment.Data, Base64FormattingOptions.InsertLineBreaks)); } AddLine(sb, "--" + boundary + "--"); } return(sb.ToString()); }