Пример #1
0
        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>();
        }
Пример #2
0
        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;
        }
Пример #3
0
        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" }));
                }
            }
        }
Пример #5
0
        /// <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");
        }
Пример #7
0
        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);
        }
Пример #8
0
        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");
            }
        }
Пример #10
0
        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"]);
            }
        }
Пример #11
0
        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);
        }
Пример #12
0
        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());
        }
Пример #13
0
        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);
        }
Пример #14
0
        /// <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);
        }
Пример #15
0
        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());
        }