summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Korber <philippkorber@gmail.com>2018-05-30 13:58:03 +0200
committerPhilipp Korber <philippkorber@gmail.com>2018-05-30 14:07:40 +0200
commit40a6c11c4a4860af62f584e4b314f389b7894fb3 (patch)
tree7d4e0b70a7634f7c3894f3cdedff937eab423485
parentb3ef57906728442dbe117570a65ce403552ee401 (diff)
chore(api)*: simplified api
[won't compile tests, see below] - use InspectEmbeddedResources + #[derive(..)] instead of strange side channel during serialize for setting content ids - provide a compose methods on `MailSendData` instead of the strange CompositionBase trait + structs - use Embedded/EmbeddedWithCId instead of Attachment, Embedding, EmbeddingWithCId,... - remove unused crates - rename mod `tempalate` => `template_enigne` - changes are not yet applied to render_template_eninge and tera bindings
-rw-r--r--Cargo.toml4
-rw-r--r--src/builder_extension.rs16
-rw-r--r--src/compositor/_impl.rs138
-rw-r--r--src/compositor/builder.rs198
-rw-r--r--src/compositor/composition_base_impl.rs82
-rw-r--r--src/compositor/impl_compose.rs160
-rw-r--r--src/compositor/mail_send_data.rs455
-rw-r--r--src/compositor/mod.rs307
-rw-r--r--src/lib.rs80
-rw-r--r--src/resource.rs315
-rw-r--r--src/resource/impl_inspect.rs199
-rw-r--r--src/resource/mod.rs160
-rw-r--r--src/template.rs104
-rw-r--r--src/template_engine.rs139
-rw-r--r--src/utils.rs10
15 files changed, 1152 insertions, 1215 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 30b2c44..92d7ef9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -15,14 +15,12 @@ repository = "https://github.com/1aim/mail-template"
mail-types = { git="https://github.com/1aim/mail-types" }
mail-common = { git="https://github.com/1aim/mail-common" }
mail-headers = { git="https://github.com/1aim/mail-headers" }
+mail-derive = { git="https://github.com/1aim/mail-derive" }
failure = "0.1.1"
futures = "0.1.14"
log = "0.3.8"
rand = "0.3.15"
-scoped-tls = "0.1.0"
-serde = "1.0.10"
-serde_derive = "1.0.10"
chrono = "0.4.0"
vec1 = { git="https://github.com/1aim/vec1" }
soft-ascii-string = "0.2.0"
diff --git a/src/builder_extension.rs b/src/builder_extension.rs
index 29e5343..9d5c7a4 100644
--- a/src/builder_extension.rs
+++ b/src/builder_extension.rs
@@ -7,8 +7,8 @@ use headers::components::{Disposition, MediaType};
use mail::{Resource, Mail, Builder};
use mail::error::OtherBuilderErrorKind;
-use ::template::BodyPart;
-use ::resource::{EmbeddingWithCId, Attachment};
+use ::template_engine::BodyPart;
+use ::resource::EmbeddedWithCId;
use ::error::{ExtendedBuilderError, ExtendedBuilderErrorKind};
@@ -31,7 +31,7 @@ pub trait BuilderExt {
fn create_with_attachments<HM>(
body: Mail,
- attachments: Vec<Attachment>,
+ attachments: Vec<EmbeddedWithCId>,
headers: HM
) -> Result<Mail, ExtendedBuilderError>
where HM: Into<Option<HeaderMap>>;
@@ -48,7 +48,7 @@ pub trait BuilderExt {
headers: HM
) -> Result<Mail, ExtendedBuilderError>
where HM: Into<Option<HeaderMap>>,
- EMB: Iterator<Item=EmbeddingWithCId> + ExactSizeIterator;
+ EMB: Iterator<Item=EmbeddedWithCId> + ExactSizeIterator;
fn create_alternate_bodies_with_embeddings<HM, EMB>(
bodies: Vec1<BodyPart>,
@@ -56,7 +56,7 @@ pub trait BuilderExt {
header: HM
) -> Result<Mail, ExtendedBuilderError>
where HM: Into<Option<HeaderMap>>,
- EMB: Iterator<Item=EmbeddingWithCId> + ExactSizeIterator;
+ EMB: Iterator<Item=EmbeddedWithCId> + ExactSizeIterator;
}
@@ -96,7 +96,7 @@ impl BuilderExt for Builder {
headers: HM
) -> Result<Mail, ExtendedBuilderError>
where HM: Into<Option<HeaderMap>>,
- EMB: Iterator<Item=EmbeddingWithCId> + ExactSizeIterator
+ EMB: Iterator<Item=EmbeddedWithCId> + ExactSizeIterator
{
match embeddings.len() {
0 => {
@@ -149,7 +149,7 @@ impl BuilderExt for Builder {
headers: HM
) -> Result<Mail, ExtendedBuilderError>
where HM: Into<Option<HeaderMap>>,
- EMB: Iterator<Item=EmbeddingWithCId> + ExactSizeIterator
+ EMB: Iterator<Item=EmbeddedWithCId> + ExactSizeIterator
{
if embeddings.len() == 0 {
@@ -179,7 +179,7 @@ impl BuilderExt for Builder {
fn create_with_attachments<HM>(
body: Mail,
- attachments: Vec<Attachment>,
+ attachments: Vec<EmbeddedWithCId>,
headers: HM
) -> Result<Mail, ExtendedBuilderError>
where HM: Into<Option<HeaderMap>>
diff --git a/src/compositor/_impl.rs b/src/compositor/_impl.rs
deleted file mode 100644
index 2608196..0000000
--- a/src/compositor/_impl.rs
+++ /dev/null
@@ -1,138 +0,0 @@
-use std::borrow::Cow;
-
-use serde::Serialize;
-use vec1::Vec1;
-
-use headers::{
- HeaderMap, HeaderTryFrom,
- _From, _To, Subject, Sender
-};
-use headers::components::Unstructured;
-use mail::{Mail, Builder};
-
-use ::utils::SerializeOnly;
-use ::resource::{
- EmbeddingWithCId, Attachment,
- with_resource_sidechanel
-};
-use ::builder_extension::BuilderExt;
-use ::template::{
- BodyPart, TemplateEngine, MailParts
-};
-use ::error::CompositionError;
-
-use super::mail_send_data::MailSendData;
-use super::CompositionBase;
-
-pub(crate) trait InnerCompositionBaseExt: CompositionBase {
-
- fn _compose_mail<D>(
- &self,
- send_data: MailSendData<
- <Self::TemplateEngine as TemplateEngine<Self::Context>>::TemplateId, D>
- ) -> Result<
- Mail,
- CompositionError<<Self::TemplateEngine as TemplateEngine<Self::Context>>::Error>
- >
- where D: Serialize
- {
- //compose display name => create Address with display name;
- let (core_headers, data, template_id) = self.process_mail_send_data(send_data)?;
-
- let MailParts { alternative_bodies, shared_embeddings, attachments }
- = self.use_template_engine(&*template_id, data)?;
-
- let mail = self.build_mail(alternative_bodies, shared_embeddings.into_iter(),
- attachments, core_headers)?;
-
- Ok(mail)
- }
-
- fn process_mail_send_data<'a, D>(
- &self,
- send_data:
- MailSendData<'a, <Self::TemplateEngine as TemplateEngine<Self::Context>>::TemplateId, D>
- ) -> Result<(
- HeaderMap,
- D,
- Cow<'a, <Self::TemplateEngine as TemplateEngine<Self::Context>>::TemplateId>
- ), CompositionError<<Self::TemplateEngine as TemplateEngine<Self::Context>>::Error>>
- where D: Serialize
- {
- let (sender, from_mailboxes, to_mailboxes, subject, template_id, data)
- = send_data.destruct();
-
- // The subject header field
- let subject = Unstructured::try_from( subject )?;
-
- // creating the header map
- let mut core_headers: HeaderMap = headers! {
- //NOTE: if we support multiple mailboxes in _From we have to
- // ensure Sender is used _iff_ there is more than one from
- _From: from_mailboxes,
- _To: to_mailboxes,
- Subject: subject
- }?;
-
- // add sender header if needed
- if let Some(sender) = sender {
- core_headers.insert(Sender, sender)?;
- }
-
- Ok((core_headers, data, template_id))
- }
-
- fn use_template_engine<D>(
- &self,
- template_id: &<Self::TemplateEngine as TemplateEngine<Self::Context>>::TemplateId,
- //TODO change to &D?
- data: D
- ) -> Result<MailParts, CompositionError<<Self::TemplateEngine as TemplateEngine<Self::Context>>::Error>>
- where D: Serialize
- {
- let ( mut mail_parts, embeddings, attachments ) =
- with_resource_sidechanel(self.context(), || -> Result<_, CompositionError<<Self::TemplateEngine as TemplateEngine<Self::Context>>::Error>> {
- // we just want to make sure that the template engine does
- // really serialize the data, so we make it so that it can
- // only do so (if we pass in the data directly it could use
- // TypeID+Transmute or TraitObject+downcast to undo the generic
- // type erasure and then create the template in some other way
- // but this would break the whole Embedding/Attachment extraction )
- let sdata = SerializeOnly::new(data);
- self.template_engine()
- .use_templates(self.context(), template_id, &sdata)
- .map_err(|err| CompositionError::Template(err))
- })?;
-
- mail_parts.attachments.extend(attachments);
- mail_parts.shared_embeddings.extend(embeddings);
- Ok(mail_parts)
- }
-
-
-
- /// uses the results of preprocessing data and templates, as well as a list of
- /// mail headers like `_From`,`To`, etc. to create a new mail
- fn build_mail<EMB>(&self,
- bodies: Vec1<BodyPart>,
- embeddings: EMB,
- attachments: Vec<Attachment>,
- core_headers: HeaderMap
- ) -> Result<Mail, CompositionError<<Self::TemplateEngine as TemplateEngine<Self::Context>>::Error>>
- where EMB: Iterator<Item=EmbeddingWithCId> + ExactSizeIterator
- {
- let mail = match attachments.len() {
- 0 => Builder::create_alternate_bodies_with_embeddings(
- bodies, embeddings, Some(core_headers))?,
- _n => Builder::create_with_attachments(
- Builder::create_alternate_bodies_with_embeddings(bodies, embeddings, None)?,
- attachments,
- Some(core_headers)
- )?
- };
- Ok(mail)
- }
-}
-
-
-impl<COT: ?Sized> InnerCompositionBaseExt for COT where COT: CompositionBase {}
diff --git a/src/compositor/builder.rs b/src/compositor/builder.rs
new file mode 100644
index 0000000..91a03f9
--- /dev/null
+++ b/src/compositor/builder.rs
@@ -0,0 +1,198 @@
+use std::borrow::{ToOwned, Cow};
+use std::fmt::{self, Debug};
+
+use vec1::Vec1;
+
+use headers::components::{
+ Mailbox, MailboxList,
+};
+
+use ::resource::InspectEmbeddedResources;
+use ::error::{MailSendDataError, MailSendDataErrorKind, WithSource, WithSourceExt};
+
+use super::MailSendData;
+
+/// Builder to create `MailSendData`
+pub struct MailSendDataBuilder<'a, TId: ?Sized + 'a, D>
+ where TId: ToOwned + Debug, TId::Owned: Debug, D: InspectEmbeddedResources + Debug
+{
+ sender: Option<Mailbox>,
+ from: Vec<Mailbox>,
+ to: Vec<Mailbox>,
+ subject: Option<String>,
+ template_id: Option<Cow<'a, TId>>,
+ data: Option<D>
+}
+
+
+
+
+
+impl<'a, TId: ?Sized + 'a, D> Debug for MailSendDataBuilder<'a, TId, D>
+ where TId: ToOwned + Debug, TId::Owned: Debug, D: InspectEmbeddedResources + Debug
+{
+ fn fmt(&self, fter: &mut fmt::Formatter) -> fmt::Result {
+ fter.debug_struct("MailSendData")
+ .field("sender", &self.sender)
+ .field("from", &self.from)
+ .field("to", &self.to)
+ .field("subject", &self.subject)
+ .field("template_id", &self.template_id)
+ .field("data", &self.data)
+ .finish()
+ }
+}
+
+// Sadly I can not used derive(Default) (it want's a bound on TId)
+// if the deriviate create is stable, I could use them for that
+impl<'a, TId: ?Sized + 'a, D> Default for MailSendDataBuilder<'a, TId, D>
+ where TId: ToOwned + Debug, TId::Owned: Debug, D: InspectEmbeddedResources + Debug
+{
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl<'a, TId: ?Sized + 'a, D> MailSendDataBuilder<'a, TId, D>
+ where TId: ToOwned + Debug, TId::Owned: Debug, D: InspectEmbeddedResources + Debug
+{
+ pub fn new() -> Self {
+ MailSendDataBuilder {
+ sender: None,
+ from: Vec::new(),
+ to: Vec::new(),
+ subject: None,
+ template_id: None,
+ data: None
+ }
+ }
+
+ /// adds a Mailbox to the list of from addresses
+ pub fn add_from(&mut self, mb: Mailbox) -> &mut Self {
+ self.from.push(mb);
+ self
+ }
+
+ /// add a Mailbox to the list of to addresses
+ pub fn add_to(&mut self, mb: Mailbox) -> &mut Self {
+ self.to.push(mb);
+ self
+ }
+
+ /// set the sender to the given mailbox and inserts it into the front of the from Mailboxes
+ ///
+ /// If a sender was set before it will be override, _but it still will be in the
+ /// from MailboxList_.
+ pub fn sender(&mut self, mb: Mailbox) -> &mut Self {
+ self.sender = Some(mb.clone());
+ self.from.insert(0, mb);
+ self
+ }
+
+ /// sets the subject as a string
+ ///
+ /// If a subject was set previously it will be overwritten.
+ pub fn subject<I>(&mut self, sbj: I) -> &mut Self
+ where I: Into<String>
+ {
+ self.subject = Some(sbj.into());
+ self
+ }
+
+ /// sets the template_id (borrowed form)
+ ///
+ /// If a template_id was set previously it will be overwritten.
+ pub fn template(&mut self, tid: &'a TId) -> &mut Self {
+ self.template_id = Some(Cow::Borrowed(tid));
+ self
+ }
+
+ /// sets the template_id (owned form)
+ ///
+ /// If a template_id was set previously it will be overwritten.
+ pub fn owned_template(&mut self, tid: <TId as ToOwned>::Owned) -> &mut Self {
+ self.template_id = Some(Cow::Owned(tid));
+ self
+ }
+
+ /// sets the template_id (cow form)
+ ///
+ /// If a template_id was set previously it will be overwritten.
+ pub fn cow_template(&mut self, tid: Cow<'a, TId>) -> &mut Self {
+ self.template_id = Some(tid);
+ self
+ }
+
+
+ /// sets the data
+ ///
+ /// If data was set previously it will be overwritten.
+ pub fn data(&mut self, data: D) -> &mut Self {
+ self.data = Some(data);
+ self
+ }
+
+ //TODO provide custom error
+ /// create `MailSendData` from this builder if possible.
+ ///
+ /// If there is only one mailbox in from no sender needs
+ /// to be set.
+ ///
+ /// # Error
+ ///
+ /// Cases in which an error is returned:
+ ///
+ /// - no data, template_id, from or to was set
+ /// - more than one from was set, but no sender was set
+ pub fn build(self)
+ -> Result<MailSendData<'a, TId, D>, WithSource<MailSendDataError, Self>>
+ {
+ match self.check_fields_are_set() {
+ Ok(_) => {},
+ Err(err) => return Err(err.with_source(self))
+ }
+
+ if self.from.len() > 1 && self.sender.is_none() {
+ return Err(MailSendDataError
+ ::from(MailSendDataErrorKind::MultiFromButNoSender)
+ .with_source(self));
+ }
+
+
+ //UNWRAP_SAFE..: we already checked that there is data
+ let from = Vec1::from_vec(self.from).unwrap();
+ let to = Vec1::from_vec(self.to).unwrap();
+ let subject = self.subject.unwrap();
+ let template_id = self.template_id.unwrap();
+ let data = self.data.unwrap();
+
+ Ok(MailSendData {
+ sender: self.sender,
+ from: MailboxList(from),
+ to: MailboxList(to),
+ subject,
+ template_id,
+ data
+ })
+ }
+
+ fn check_fields_are_set(&self) -> Result<(), MailSendDataError> {
+ use self::MailSendDataErrorKind::*;
+ let kind =
+ if self.from.is_empty() {
+ MissingFrom
+ } else if self.to.is_empty() {
+ MissingTo
+ } else if self.subject.is_none() {
+ MissingSubject
+ } else if self.template_id.is_none() {
+ MissingTemplateId
+ } else if self.data.is_none() {
+ MissingTemplateData
+ } else {
+ return Ok(());
+ };
+
+ Err(MailSendDataError::from(kind))
+ }
+}
diff --git a/src/compositor/composition_base_impl.rs b/src/compositor/composition_base_impl.rs
deleted file mode 100644
index 7755744..0000000
--- a/src/compositor/composition_base_impl.rs
+++ /dev/null
@@ -1,82 +0,0 @@
-use std::sync::Arc;
-
-use template::TemplateEngine;
-use mail::Context;
-
-use super::CompositionBase;
-
-pub struct SimpleCompositionBase<CTX, TE> {
- template_engine: TE,
- context: CTX
-}
-
-impl<CTX, TE> SimpleCompositionBase<CTX, TE>
- where TE: TemplateEngine<CTX>, CTX: Context
-{
- pub fn new(context: CTX, template_engine: TE) -> Self {
- SimpleCompositionBase { template_engine, context }
- }
-
-
- pub fn context_mut(&mut self) -> &mut CTX {
- &mut self.context
- }
-
- pub fn template_engine_mut(&mut self) -> &TE {
- &mut self.template_engine
- }
-}
-
-
-impl<CTX, TE> CompositionBase for SimpleCompositionBase<CTX, TE>
- where TE: TemplateEngine<CTX>, CTX: Context
-{
- type Context = CTX;
- type TemplateEngine = TE;
-
- fn template_engine(&self) -> &Self::TemplateEngine {
- &self.template_engine
- }
- fn context(&self) -> &Self::Context {
- &self.context
- }
-}
-
-pub struct SharedCompositionBase<CTX, TE> {
- template_engine: Arc<TE>,
- context: CTX
-}
-
-impl<TE, CTX> SharedCompositionBase<CTX, TE>
- where TE: TemplateEngine<CTX>, CTX: Context
-{
- pub fn new(context: CTX, template_engine: TE) -> Self {
- SharedCompositionBase {
- template_engine: Arc::new(template_engine),
- context
- }
- }
-}
-
-impl<TE, CTX> CompositionBase for SharedCompositionBase<CTX, TE>
- where TE: TemplateEngine<CTX>, CTX: Context
-{
- type TemplateEngine = TE;
- type Context = CTX;
-
- fn template_engine(&self) -> &Self::TemplateEngine { &self.template_engine }
- fn context(&self) -> &Self::Context { &self.context }
-}
-
-
-impl<'a, TE: 'a, CTX: 'a> CompositionBase for (&'a CTX, &'a TE)
- where TE: TemplateEngine<CTX>, CTX: Context
-{
- type Context = CTX;
- type TemplateEngine = TE;
-
- fn template_engine(&self) -> &Self::TemplateEngine { self.1 }
- fn context(&self) -> &Self::Context { self.0 }
-}
-
-
diff --git a/src/compositor/impl_compose.rs b/src/compositor/impl_compose.rs
new file mode 100644
index 0000000..fc6663d
--- /dev/null
+++ b/src/compositor/impl_compose.rs
@@ -0,0 +1,160 @@
+use std::borrow::Cow;
+use std::marker::PhantomData;
+use vec1::Vec1;
+
+use headers::{
+ HeaderMap, HeaderTryFrom,
+ _From, _To, Subject, Sender
+};
+use headers::components::Unstructured;
+use mail::{Mail, Builder, Context};
+
+use ::resource::{
+ Embedded, EmbeddedWithCId,
+ InspectEmbeddedResources, Disposition
+};
+use ::builder_extension::BuilderExt;
+use ::template_engine::{
+ BodyPart, TemplateEngine, MailParts
+};
+use ::error::CompositionError;
+
+use super::MailSendData;
+
+pub(crate) fn compose_mail<'a, C, E, D>(
+ ctx: &C,
+ engine: &E,
+ send_data: MailSendData<'a, E::TemplateId, D>
+) -> Result<Mail, CompositionError<E::Error>>
+ where C: Context, E: TemplateEngine<C, D>, D: InspectEmbeddedResources
+{
+ (Ctx { ctx, engine, _p: PhantomData }).compose_mail(send_data)
+}
+
+struct Ctx<'a, 'b, C: 'a, E: 'b, D>
+ where C: Context, E: TemplateEngine<C, D>, D: InspectEmbeddedResources
+{
+ ctx: &'a C,
+ engine: &'b E,
+ _p: PhantomData<D>
+}
+
+impl<'a, 'b, C: 'a, E: 'b, D> Copy for Ctx<'a, 'b, C, E, D>
+ where C: Context, E: TemplateEngine<C, D>, D: InspectEmbeddedResources
+{}
+
+impl<'a, 'b, C: 'a, E: 'b, D> Clone for Ctx<'a, 'b, C, E, D>
+ where C: Context, E: TemplateEngine<C, D>, D: InspectEmbeddedResources
+{
+ fn clone(&self) -> Self {
+ Ctx { ctx: self.ctx, engine: self.engine, _p: self._p }
+ }
+}
+
+impl<'a, 'b, C, E, D> Ctx<'a, 'b, C, E, D>
+ where C: Context, E: TemplateEngine<C, D>, D: InspectEmbeddedResources
+{
+
+ fn compose_mail(self, send_data: MailSendData<E::TemplateId, D>)
+ -> Result<Mail, CompositionError<E::Error>>
+ {
+ //compose display name => create Address with display name;
+ let (core_headers, data, template_id) = self.process_mail_send_data(send_data)?;
+
+ let MailParts { alternative_bodies, shared_embeddings, attachments }
+ = self.use_template_engine(&*template_id, data)?;
+
+ let mail = self.build_mail(alternative_bodies, shared_embeddings.into_iter(),
+ attachments, core_headers)?;
+
+ Ok(mail)
+ }
+
+ fn process_mail_send_data<'n>(
+ self,
+ send_data:
+ MailSendData<'n, E::TemplateId, D>
+ ) -> Result<(
+ HeaderMap,
+ D,
+ Cow<'n, E::TemplateId>
+ ), CompositionError<E::Error>>
+ where D: InspectEmbeddedResources
+ {
+ let (sender, from_mailboxes, to_mailboxes, subject, template_id, data)
+ = send_data.destruct();
+
+ // The subject header field
+ let subject = Unstructured::try_from( subject )?;
+
+ // creating the header map
+ let mut core_headers: HeaderMap = headers! {
+ //NOTE: if we support multiple mailboxes in _From we have to
+ // ensure Sender is used _iff_ there is more than one from
+ _From: from_mailboxes,
+ _To: to_mailboxes,
+ Subject: subject
+ }?;
+
+ // add sender header if needed
+ if let Some(sender) = sender {
+ core_headers.insert(Sender, sender)?;
+ }
+
+ Ok((core_headers, data, template_id))
+ }
+
+ fn use_template_engine(
+ self,
+ template_id: &E::TemplateId,
+ //TODO change to &D?
+ data: D
+ ) -> Result<MailParts, CompositionError<E::Error>>
+ where D: InspectEmbeddedResources
+ {
+ let mut data = data;
+ let mut embeddings = Vec::new();
+ let mut attachments = Vec::new();
+
+ data.inspect_resources_mut(&mut |embedded: &mut Embedded| {
+ let embedded_wcid = embedded.assure_content_id_and_copy(self.ctx);
+ match embedded_wcid.disposition() {
+ Disposition::Inline => embeddings.push(embedded_wcid),
+ Disposition::Attachment => attachments.push(embedded_wcid)
+ }
+ });
+
+ let mut mail_parts = self.engine
+ .use_template(template_id, &data, self.ctx)
+ .map_err(|err| CompositionError::Template(err))?;
+
+ mail_parts.attachments.extend(attachments);
+ mail_parts.shared_embeddings.extend(embeddings);
+ Ok(mail_parts)
+ }
+
+
+
+ /// uses the results of preprocessing data and templates, as well as a list of
+ /// mail headers like `_From`,`To`, etc. to create a new mail
+ fn build_mail<EMB>(
+ self,
+ bodies: Vec1<BodyPart>,
+ embeddings: EMB,
+ attachments: Vec<EmbeddedWithCId>,
+ core_headers: HeaderMap
+ ) -> Result<Mail, CompositionError<E::Error>>
+ where EMB: Iterator<Item=EmbeddedWithCId> + ExactSizeIterator
+ {
+ let mail = match attachments.len() {
+ 0 => Builder::create_alternate_bodies_with_embeddings(
+ bodies, embeddings, Some(core_headers))?,
+ _n => Builder::create_with_attachments(
+ Builder::create_alternate_bodies_with_embeddings(bodies, embeddings, None)?,
+ attachments,
+ Some(core_headers)
+ )?
+ };
+ Ok(mail)
+ }
+}
diff --git a/src/compositor/mail_send_data.rs b/src/compositor/mail_send_data.rs
deleted file mode 100644
index 6168513..0000000
--- a/src/compositor/mail_send_data.rs
+++ /dev/null
@@ -1,455 +0,0 @@
-use std::borrow::{ToOwned, Cow};
-use std::sync::Arc;
-use std::ops::Deref;
-use std::fmt::{self, Debug};
-
-use serde::Serialize;
-use vec1::Vec1;
-
-use headers::HeaderTryFrom;
-use headers::error::ComponentCreationError;
-use headers::components::{
- Mailbox, MailboxList,
- Phrase, Email
-};
-
-use ::error::{MailSendDataError, MailSendDataErrorKind, WithSource, WithSourceExt};
-
-/// A type containing all per-Mail specific information
-///
-/// The contained information is:
-///
-/// - sender (if any)
-/// - from (1+ Mailboxes)
-/// - to (1+ Mailboxes)
-/// - subject (a String)
-/// - template (a template id, or more concrete `Cow<'a, TId>`, often a cow string)
-/// - data (the data for the template)
-///
-/// To create a `MailSendData` instance use the `MailSendDataBuilder`.
-///
-/// All information in a `MailSendData` instance can be accesses for reading,
-/// but some constraints are set on modifying it so that following constraints
-/// are uphold:
-///
-/// 1. if there is more than one Mailbox in from then there is a sender
-/// 2. there has to be at last one Mailbox in from
-/// 3. there has to be at last one Mailbox in to
-///
-/// # Example (Construction)
-///
-/// ```
-/// # extern crate mail_common as common;
-/// # extern crate mail_headers as headers;
-/// # extern crate mail_types as mail;
-/// # extern crate mail_template as compose;
-/// # use std::collections::HashMap;
-/// # use headers::HeaderTryFrom;
-/// # use headers::components::{Mailbox, Email};
-/// # use compose::MailSendDataBuilder;
-/// #
-/// # fn main() {
-/// #
-/// # let me = Email::try_from("me@thisisme.mememe").unwrap().into();
-/// # let an_additional_from = Email::try_from("notme@thisisntme.notmenotmenotme").unwrap().into();
-/// # let some_one_else = Email::try_from("other@person.that_is").unwrap().into();
-/// # let test_data = HashMap::<&'static str, String>::new();
-/// let mut builder = MailSendDataBuilder::new();
-/// builder
-/// .sender(me)
-/// .add_from(an_additional_from)
-/// .add_to(some_one_else)
-/// .subject("Una test")
-/// .template("template_a1_b")
-/// .data(test_data);
-///
-/// // build() consumes the builder so we can not chain
-/// // it with the the other calls to the builder
-/// let mail_send_data = builder.build().unwrap();
-/// # }
-/// ```
-///
-pub struct MailSendData<'a, TId: ?Sized + 'a, D>
- where TId: ToOwned, D: Serialize
-{
- sender: Option<Mailbox>,
- from: MailboxList,
- to: MailboxList,
- subject: String,
- template_id: Cow<'a, TId>,
- data: D
-}
-
-impl<'a, TId: ?Sized + 'a, D> Debug for MailSendData<'a, TId, D>
- where TId: ToOwned + Debug, <TId as ToOwned>::Owned: Debug, D: Serialize + Debug
-{
- fn fmt(&self, fter: &mut fmt::Formatter) -> fmt::Result {
- fter.debug_struct("MailSendData")
- .field("sender", &self.sender)
- .field("from", &self.from)
- .field("to", &self.to)
- .field("subject", &self.subject)
- .field("template_id", &self.template_id)
- .field("data", &self.data)
- .finish()
- }
-}
-
-
-impl<'a, TId: ?Sized + 'a, D> MailSendData<'a, TId, D>
- where TId: ToOwned, D: Serialize
-{
- /// create a simple MailSendData with a sing From and a single To Mailbox
- pub fn simple_new<I>(
- from: Mailbox, to: Mailbox,
- subject: I,
- template_id: Cow<'a, TId>, data: D
- ) -> Self
- where I: Into<String>
- {
- MailSendData {
- sender: None,
- from: MailboxList(vec1![from]),
- to: MailboxList(vec1![to]),
- subject: subject.into(),
- template_id, data
- }
- }
-
- /// returns a reference to a explicity set sender or else the first (and only) from mailbox
- pub fn sender(&self) -> &Mailbox {
- self.sender.as_ref().unwrap_or_else(|| self.from.first())
- }
-
-
- pub fn _from(&self) -> &MailboxList {
- &self.from
- }
-
- /// Allows mutating from Mailboxes
- ///
- /// this does only expose a &mut Slice of Mailboxes, instead of a &mut MailboxList
- /// to make sure that no from mailbox can be added as sender might be empty
- pub fn _from_mut(&mut self) -> &mut [Mailbox] {
- &mut self.from
- }
-
- //TODO add set_sender method
- //TODO add try_add_from method failing if sender is None
- //TODO maybe add a try_set_from(MailboxList) too
-
- pub fn _to(&self) -> &MailboxList {
- &self.to
- }
-
- pub fn _to_mut(&mut self) -> &mut MailboxList {
- &mut self.to
- }
-
- pub fn subject(&self) -> &str {
- &self.subject
- }
-
- pub fn subject_mut(&mut self) -> &mut String {
- &mut self.subject
- }
-
- pub fn template(&self) -> &TId {
- &self.template_id
- }
-
- pub fn template_mut(&mut self) -> &mut Cow<'a, TId> {
- &mut self.template_id
- }
-
- pub fn data(&self) -> &D {
- &self.data
- }
-
- pub fn data_mut(&mut self) -> &mut D {
- &mut self.data
- }
-
- pub(crate) fn destruct(self) ->
- (Option<Mailbox>, MailboxList, MailboxList, String, Cow<'a, TId>, D)
- {
- //use let destruction to make it more refactoring resistend
- let MailSendData { sender, from, to, subject, template_id, data } = self;
- (sender, from, to, subject, template_id, data)
- }
-
- pub fn auto_gen_display_names<NC>(&mut self, name_composer: NC) -> Result<(), ComponentCreationError>
- where NC: NameComposer<D>
- {
- let data = &mut self.data;
- {
- let mut from_auto_gen = |email: &Email| {
- match name_composer.compose_from_name(email, data)? {
- Some(name) => Ok(Some(Phrase::try_from(name)?)),
- None => Ok(None),
- }
- };
-
- if let Some(sender) = self.sender.as_mut() {
- sender.auto_gen_name(&mut from_auto_gen)?;
- }
-
- for elem in self.from.iter_mut() {
- elem.auto_gen_name(&mut from_auto_gen)?;
- }
- }
-
- for elem in self.to.iter_mut() {
- elem.auto_gen_name(|email| {
- match name_composer.compose_to_name(email, data)? {
- Some(name) => Ok(Some(Phrase::try_from(name)?)),
- None => Ok(None),
- }
- })?;
- }
-
- Ok(())
- }
-}
-
-pub trait NameComposer<D> {
- /// generates a display name used in a From header based on email address and mails data
- ///
- /// The data is passed in as a `&mut` ref so that the generated name can
- /// also be made available to the template engine, e.g. for generating
- /// greetings. The data should _not_ be changed in any other way.
- ///
- /// The composer can decide to not generate a display name if, e.g. there
- /// is not enough information to doe so.
- ///
- /// # Error
- ///
- /// A error can be returned if generated the name failed, e.g. because
- /// a query to a database faile