/// <summary> /// Add an attachment to this e-mail. /// </summary> /// <param name="EMailBodypart">An attachment.</param> public T AddAttachment <T>(EMailBodypart EMailBodypart) where T : AbstractEMailBuilder { _Attachments.Add(EMailBodypart); return((T)this); }
/// <summary> /// Parse an e-mail from the given enumeration of strings. /// </summary> /// <param name="MailText">An enumeration of strings.</param> private EMail(IEnumerable <String> MailText) : this(MailText.TakeWhile(line => line.IsNotNullOrEmpty()). AggregateIndentedLines(). ToKeyValuePairs(':')) { Body = new EMailBodypart(MailText); }
/// <summary> /// Create a new e-mail based on the given e-mail builder. /// </summary> /// <param name="MailBuilder">An e-mail builder.</param> public EMail(AbstractEMailBuilder MailBuilder) : this(MailBuilder. EncodeBodyparts(). // Copy only everything which is not related to the e-mail body! MailHeaders.Where(header => !header.Key.ToLower().StartsWith("content")). Concat(MailBuilder.Body.MailHeaders)) { //ToDo: Do a real deep-copy here! Body = MailBuilder.Body; //ToDo: Work-aroung for PGP/GPG! this.From = MailBuilder.From; this.To = MailBuilder.To; this.Cc = MailBuilder.Cc; }
/// <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); }
/// <summary> /// Parse the e-mail from the given text lines. /// </summary> /// <param name="MailText">The E-Mail as an enumeration of strings.</param> public AbstractEMailBuilder(IEnumerable <String> MailText) : base(MailText) { this._Body = new EMailBodypart(MailText); }
/// <summary> /// Parse the e-mail from the given e-mail. /// </summary> /// <param name="EMail">An e-mail.</param> public AbstractEMailBuilder(EMail EMail) : base(EMail) { this._Body = new EMailBodypart(EMail.ToText); }
/// <summary> /// Parse an e-mail from the given enumeration of strings. /// </summary> /// <param name="MailText">An enumeration of strings.</param> private EMail(IEnumerable<String> MailText) : this(MailText.TakeWhile(line => line.IsNotNullOrEmpty()). AggregateIndentedLines(). ToKeyValuePairs(':')) { Body = new EMailBodypart(MailText); }