public void ThrowIfInvalid()
        {
            Recipients.ThrowIfNullOrEmpty(nameof(Recipients));
            Subject.ThrowIfNullOrEmpty(nameof(Subject));
            ViewPath.ThrowIfNullOrEmpty(nameof(ViewPath));

            foreach (string recipient in Recipients)
            {
                if (!StringHelpers.IsValidEmail(recipient))
                {
                    throw new InvalidOperationException($"Email '{recipient}' is invalid");
                }
            }

            if (Cc.Any())
            {
                foreach (string cc in Cc)
                {
                    if (!StringHelpers.IsValidEmail(cc))
                    {
                        throw new InvalidOperationException($"Email '{cc}' is invalid");
                    }
                }
            }
        }
Beispiel #2
0
        public void ThrowIfInvalid()
        {
            Recipients.ThrowIfNullOrEmpty(nameof(Recipients));
            Subject.ThrowIfNullOrEmpty(nameof(Subject));
            ViewPath.ThrowIfNullOrEmpty(nameof(ViewPath));

            foreach (string recipient in Recipients)
            {
                if (!StringHelpers.IsValidEmail(recipient))
                {
                    throw new InvalidOperationException($"Email '{recipient}' is invalid");
                }
            }

            if (Cc.Any())
            {
                foreach (string cc in Cc)
                {
                    if (!StringHelpers.IsValidEmail(cc))
                    {
                        throw new InvalidOperationException($"Email '{cc}' is invalid");
                    }
                }

                Cc = Cc.Where(x => !Recipients.Contains(x)).ToArray();
            }

            if (HiddenCc.Any())
            {
                foreach (string cc in HiddenCc)
                {
                    if (!StringHelpers.IsValidEmail(cc))
                    {
                        throw new InvalidOperationException($"Email '{cc}' is invalid");
                    }
                }

                HiddenCc = HiddenCc
                           .Where(x => !Cc.Contains(x))
                           .Where(x => !Recipients.Contains(x)).ToArray();
            }
        }
Beispiel #3
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);
        }
Beispiel #4
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());
        }