diff --git a/composer.json b/composer.json
index 193f1c953a0e4950f3a15268957e772c20ee9513..672f320aa37e59bdd196d713529ff9fb25ce8e1a 100644
--- a/composer.json
+++ b/composer.json
@@ -41,16 +41,18 @@
     "require-dev": {
         "10up/wp_mock": "*",
         "mockery/mockery": "*",
-        "phpunit/phpunit": "<7",
-        "wp-coding-standards/wpcs": "^2.3.0",
-        "squizlabs/php_codesniffer": "^3.0.2"
+        "phpunit/phpunit": "<7"
     },
     "autoload": {
         "psr-4": {
             "WPDesk\\Library\\WPEmail\\": "src"
         }
     },
-    "autoload-dev": {},
+    "autoload-dev": {
+        "psr-4": {
+            "Tests\\Mailer\\": "tests/unit"
+        }
+    },
     "extra": {
         "text-domain": "wp-email",
         "translations-folder": "lang",
diff --git a/phpunit-unit.xml b/phpunit-unit.xml
index f3b7ead97601294e87575236952d21711e0cec07..74290fab09e79ac5a90ecbef0fb675d363c99992 100644
--- a/phpunit-unit.xml
+++ b/phpunit-unit.xml
@@ -1,21 +1,17 @@
 <phpunit bootstrap="tests/unit/bootstrap.php">
     <testsuites>
-        <testsuite>
-            <directory prefix="Test_" suffix=".php">./tests/unit/</directory>
+        <testsuite name="unit">
+            <directory suffix="Test.php">./tests/unit/</directory>
         </testsuite>
     </testsuites>
 
     <filter>
         <whitelist>
             <directory suffix=".php">src</directory>
+            <exclude>
+                <directory suffix=".php">src/templates</directory>
+            </exclude>
         </whitelist>
     </filter>
 
-    <logging>
-        <log type="junit" target="build-coverage/report.junit.xml"/>
-        <log type="coverage-html" target="build-coverage/coverage" charset="UTF-8" yui="true" highlight="true"/>
-        <log type="coverage-text" target="build-coverage/coverage.txt"/>
-        <log type="coverage-clover" target="build-coverage/clover.xml"/>
-    </logging>
-
 </phpunit>
diff --git a/src/Abstracts/ConditionInterface.php b/src/Abstracts/ConditionInterface.php
deleted file mode 100644
index 94bc2569919fd1e363d3062fc17a5eabe7f96711..0000000000000000000000000000000000000000
--- a/src/Abstracts/ConditionInterface.php
+++ /dev/null
@@ -1,11 +0,0 @@
-<?php
-
-namespace WPDesk\Library\WPEmail\Abstracts;
-
-use WPDesk\View\Renderer\Renderer;
-
-interface ConditionInterface {
-
-    public function is_valid(): bool;
-
-}
diff --git a/src/Abstracts/Email.php b/src/Abstracts/Email.php
new file mode 100644
index 0000000000000000000000000000000000000000..d21f2bb7ec8f7d3bc2af47af6a784e82d8444959
--- /dev/null
+++ b/src/Abstracts/Email.php
@@ -0,0 +1,213 @@
+<?php
+
+namespace WPDesk\Library\WPEmail\Abstracts;
+
+use Exception;
+
+class Email {
+
+    /**
+     * @var array
+     */
+    private $recipients = [];
+
+    /**
+     * @var string
+     */
+    private $subject = '';
+
+    /**
+     * @var array
+     */
+    private $attachments = [];
+
+    /**
+     * @var string
+     */
+    private $content = '';
+
+    /**
+     * @var array
+     */
+    private $headers = [ 'Content-Type' => 'text/html' ];
+
+    /**
+     * @var string
+     */
+    private $from_email;
+
+    /**
+     * @var string
+     */
+    private $from_name;
+
+    /**
+     * @var array
+     */
+    private $template_attributes;
+
+    /**
+     * @param string $from_email
+     *
+     * @return self
+     */
+    public function set_from( string $from_email ): self {
+        $this->from_email = $from_email;
+
+        return $this;
+    }
+
+    /**
+     * @return string
+     */
+    public function get_from(): string {
+        return $this->from_email;
+    }
+
+    /**
+     * @param string $from_name
+     *
+     * @return self
+     */
+    public function set_from_name( string $from_name ): self {
+        $this->from_name = $from_name;
+
+        return $this;
+    }
+
+    /**
+     * @return string
+     */
+    public function get_from_name(): string {
+        return wp_specialchars_decode( esc_html( $this->from_name ), ENT_QUOTES );
+    }
+
+    /**
+     * @param string $subject
+     *
+     * @return self
+     */
+    public function set_subject( string $subject ): self {
+        $this->subject = $subject;
+
+        return $this;
+    }
+
+    /**
+     * @return string
+     * @throws Exception
+     */
+    public function get_subject(): string {
+        return $this->subject;
+    }
+
+    /**
+     * @param array $recipients
+     *
+     * @return self
+     */
+    public function set_recipients( array $recipients = [] ): self {
+        $this->recipients = $recipients;
+
+        return $this;
+    }
+
+    /**
+     * @return string[]
+     */
+    public function get_recipients(): array {
+        return $this->recipients;
+    }
+
+    public function set_header( string $header, string $value ): self {
+        $this->headers[ $header ] = $value;
+
+        return $this;
+    }
+
+    /** @return string[] */
+    public function get_headers(): array {
+        $result = [];
+        foreach ( $this->headers as $header => $value ) {
+            $result[] = "$header: $value";
+        }
+
+        return $result;
+    }
+
+    public function get_header( string $header ): string {
+        return $this->headers[ $header ] ?? '';
+    }
+
+    /**
+     * @param array $attachments
+     *
+     * @return self
+     */
+    public function set_attachments( array $attachments ): self {
+        $this->attachments = $attachments;
+
+        return $this;
+    }
+
+    /**
+     * @return array
+     */
+    public function get_attachments(): array {
+        return $this->attachments;
+    }
+
+    public function is_html(): bool {
+        return $this->get_header( 'Content-Type' ) === 'text/html';
+    }
+
+    /**
+     * @return string
+     */
+    public function set_content_type( $type = 'html' ): self {
+        switch ( $type ) {
+            case 'plain':
+                $content_type = 'text/plain';
+                break;
+            case 'multipart':
+                $content_type = 'multipart/alternative';
+                break;
+            default:
+                $content_type = 'text/html';
+        }
+
+        $this->set_header( 'Content-Type', $content_type );
+
+        return $this;
+    }
+
+    /**
+     * @param string $content
+     *
+     * @return self
+     */
+    public function set_content( string $content ): self {
+        $this->content = $content;
+
+        return $this;
+    }
+
+    /**
+     * @return string
+     * @throws Exception
+     */
+    public function get_content(): string {
+        return $this->content;
+    }
+
+    public function set_template_attributes( string $name, string $value ): self {
+        $this->template_attributes[ $name ] = $value;
+
+        return $this;
+    }
+
+    public function get_template_attributes(): array {
+        return $this->template_attributes;
+    }
+
+}
diff --git a/src/Abstracts/EmailAbstract.php b/src/Abstracts/EmailAbstract.php
deleted file mode 100644
index 2e326eadfb8ab503ee18bfb08203ef69cc4fa99c..0000000000000000000000000000000000000000
--- a/src/Abstracts/EmailAbstract.php
+++ /dev/null
@@ -1,306 +0,0 @@
-<?php
-
-namespace WPDesk\Library\WPEmail\Abstracts;
-
-use Exception;
-
-abstract class EmailAbstract implements EmailInterface {
-
-    /**
-     * @var bool
-     */
-    private $is_enable;
-
-    /**
-     * @var array
-     */
-    private $recipients = [];
-
-    /**
-     * @var array
-     */
-    private $placeholders = [];
-
-    /**
-     * @var string
-     */
-    private $subject = '';
-
-    /**
-     * @var string
-     */
-    private $heading = '';
-
-    /**
-     * @var array
-     */
-    private $attachments = [];
-
-    /**
-     * @var string
-     */
-    private $content = '';
-
-    /**
-     * @var string
-     */
-    private $type = 'html';
-
-    /**
-     * @var array
-     */
-    private $headers = [ 'Content-Type: text/html; charset=UTF-8' ];
-
-    /**
-     * @var string
-     */
-    private $from_email;
-
-    /**
-     * @var string
-     */
-    private $from_name;
-
-    /**
-     * @return string
-     */
-    abstract public function get_id(): string;
-
-    /**
-     * @return string
-     */
-    public function get_template_name(): string {
-        return 'default';
-    }
-
-    /**
-     * @return string
-     */
-    public function get_from(): string {
-        return sanitize_email( $this->from_email );
-    }
-
-    /**
-     * @param string $from_email
-     *
-     * @return self
-     */
-    public function set_from( string $from_email ): self {
-        $this->from_email = $from_email;
-
-        return $this;
-    }
-
-    /**
-     * @param string $from_name
-     *
-     * @return self
-     */
-    public function set_from_name( string $from_name ): self {
-        $this->from_name = $from_name;
-
-        return $this;
-    }
-
-    /**
-     * @return string
-     */
-    public function get_from_name(): string {
-        return wp_specialchars_decode( esc_html( $this->from_name ), ENT_QUOTES );
-    }
-
-    /**
-     * @return bool
-     */
-    public function get_is_enable(): bool {
-        return $this->is_enable;
-    }
-
-    /**
-     * @param $enable
-     *
-     * @return EmailAbstract
-     */
-    public function set_is_enable( $enable ): self {
-        $this->is_enable = $enable;
-
-        return $this;
-    }
-
-    /**
-     * @param array $placeholders
-     *
-     * @return self
-     */
-    public function set_placeholders( array $placeholders = [] ): self {
-        $this->placeholders = array_merge( $this->placeholders, $placeholders );
-
-        return $this;
-    }
-
-    /**
-     * @return string[]
-     */
-    public function get_placeholders(): array {
-        return $this->placeholders;
-    }
-
-    /**
-     * @param string $subject
-     *
-     * @return self
-     */
-    public function set_subject( string $subject ): self {
-        $this->subject = $subject;
-
-        return $this;
-    }
-
-    /**
-     * @return string
-     * @throws Exception
-     */
-    public function get_subject(): string {
-        if ( ! $this->subject ) {
-            throw new Exception( 'Empty email subject' );
-        }
-
-        return $this->replace_placeholders( $this->subject );
-    }
-
-    /**
-     * @param string $heading
-     *
-     * @return self
-     */
-    public function set_heading( string $heading ): self {
-        $this->heading = $heading;
-
-        return $this;
-    }
-
-    /**
-     * @return string
-     */
-    public function get_heading(): string {
-        return $this->replace_placeholders( $this->heading );
-    }
-
-    /**
-     * @param array $recipients
-     *
-     * @return self
-     */
-    public function set_recipients( array $recipients = [] ): self {
-        $this->recipients = $recipients;
-
-        return $this;
-    }
-
-    /**
-     * @return string[]
-     */
-    public function get_recipients(): array {
-        return $this->recipients;
-    }
-
-    /**
-     * @param array $headers
-     *
-     * @return self
-     */
-    public function set_headers( array $headers = [] ): self {
-        $this->headers = $headers;
-
-        return $this;
-    }
-
-    /**
-     * @return string[]
-     */
-    public function get_headers(): array {
-        return $this->headers;
-    }
-
-    /**
-     * @param array $attachments
-     *
-     * @return self
-     */
-    public function set_attachments( array $attachments ): self {
-        $this->attachments = $attachments;
-
-        return $this;
-    }
-
-    /**
-     * @return array
-     */
-    public function get_attachments(): array {
-        return $this->attachments;
-    }
-
-    /**
-     * @param string $type
-     *
-     * @return self
-     */
-    public function set_type( string $type = 'html' ): self {
-        $this->type = $type;
-
-        return $this;
-    }
-
-    /**
-     * @return string
-     */
-    public function get_type(): string {
-        return $this->type;
-    }
-
-    /**
-     * @return string
-     */
-    public function get_content_type(): string {
-        switch ( $this->get_type() ) {
-            case 'html':
-                return 'text/html';
-            case 'multipart':
-                return 'multipart/alternative';
-            default:
-                return 'text/plain';
-        }
-    }
-
-    /**
-     * @param string $content
-     *
-     * @return self
-     */
-    public function set_content( string $content ): self {
-        $this->content = $content;
-
-        return $this;
-    }
-
-    /**
-     * @return string
-     * @throws Exception
-     */
-    public function get_content(): string {
-        return $this->replace_placeholders( $this->content );
-    }
-
-    /**
-     * @return array|string|string[]
-     */
-    protected function replace_placeholders( string $string ): string {
-        if ( empty( $this->placeholders ) ) {
-            return $string;
-        }
-
-        return (string) str_replace( array_keys( $this->placeholders ), array_values( $this->placeholders ), $string );
-    }
-
-
-}
diff --git a/src/Abstracts/EmailInterface.php b/src/Abstracts/EmailInterface.php
deleted file mode 100644
index 61a4ea8a251125fdfef9659567cb7696648a24ac..0000000000000000000000000000000000000000
--- a/src/Abstracts/EmailInterface.php
+++ /dev/null
@@ -1,101 +0,0 @@
-<?php
-
-namespace WPDesk\Library\WPEmail\Abstracts;
-
-interface EmailInterface {
-
-    /**
-     * Define unique email ID.
-     *
-     * @return string
-     */
-    public function get_id(): string;
-
-    /**
-     * Get template name.
-     *
-     * @return string
-     */
-    public function get_template_name(): string;
-
-    /**
-     * @return string
-     */
-    public function get_from(): string;
-
-    /**
-     * @return string
-     */
-    public function get_from_name(): string;
-
-    /**
-     * Is enable.
-     *
-     * @return bool
-     */
-    public function get_is_enable(): bool;
-
-    /**
-     * Get defined placeholders.
-     *
-     * @return array
-     */
-    public function get_placeholders(): array;
-
-    /**
-     * Get email subject.
-     *
-     * @return string
-     */
-    public function get_subject(): string;
-
-    /**
-     * Get email heading.
-     *
-     * @return string
-     */
-    public function get_heading(): string;
-
-    /**
-     * Get valid recipients.
-     *
-     * @return string[]
-     */
-    public function get_recipients(): array;
-
-    /**
-     * Get email headers.
-     *
-     * @return string[]
-     */
-    public function get_headers(): array;
-
-    /**
-     * Get email attachments.
-     *
-     * @return array
-     */
-    public function get_attachments(): array;
-
-    /**
-     * Get email type.
-     *
-     * @return string
-     */
-    public function get_type(): string;
-
-    /**
-     * Get content type.
-     *
-     * @return string
-     */
-    public function get_content_type(): string;
-
-    /**
-     * Get email content.
-     *
-     * @return string
-     */
-    public function get_content(): string;
-
-}
diff --git a/src/Abstracts/Mailer.php b/src/Abstracts/Mailer.php
new file mode 100644
index 0000000000000000000000000000000000000000..0602ff20db09f65bf87632c259a677d28c75a367
--- /dev/null
+++ b/src/Abstracts/Mailer.php
@@ -0,0 +1,15 @@
+<?php
+
+namespace WPDesk\Library\WPEmail\Abstracts;
+
+use WPDesk\Library\WPEmail\Exceptions\MailerException;
+
+interface Mailer {
+
+    /**
+     * @throws MailerException
+     */
+    public function send( Email $email ): void;
+
+}
+
diff --git a/src/MailerException.php b/src/Exceptions/MailerException.php
similarity index 88%
rename from src/MailerException.php
rename to src/Exceptions/MailerException.php
index 9dd31547c57459530437bcfe38f7bc95c2201255..6c005cd4975cdb253742004f5b71ce244db0c1b5 100644
--- a/src/MailerException.php
+++ b/src/Exceptions/MailerException.php
@@ -2,7 +2,7 @@
 
 declare( strict_types=1 );
 
-namespace WPDesk\Library\WPEmail;
+namespace WPDesk\Library\WPEmail\Exceptions;
 
 class MailerException extends \RuntimeException {
 
diff --git a/src/Helpers/Template.php b/src/Helpers/ColorConversion.php
similarity index 99%
rename from src/Helpers/Template.php
rename to src/Helpers/ColorConversion.php
index 0096d9d3824df52ef1c611caf92088d20918fc22..e8242ee402eaa058e124241c4dbda8d4a13337d5 100644
--- a/src/Helpers/Template.php
+++ b/src/Helpers/ColorConversion.php
@@ -2,7 +2,7 @@
 
 namespace WPDesk\Library\WPEmail\Helpers;
 
-class Template {
+class ColorConversion {
 
     /**
      * Determine whether a hex color is light.
diff --git a/src/Helpers/HTML.php b/src/Helpers/StyleInliner.php
similarity index 63%
rename from src/Helpers/HTML.php
rename to src/Helpers/StyleInliner.php
index aace0afe080492ebe87a68601ae58f6d332b4c80..9068deeddfad4b16d4da360d196d05c1035b2ae7 100644
--- a/src/Helpers/HTML.php
+++ b/src/Helpers/StyleInliner.php
@@ -6,9 +6,9 @@ use Pelago\Emogrifier\CssInliner;
 use Pelago\Emogrifier\HtmlProcessor\CssToAttributeConverter;
 use Pelago\Emogrifier\HtmlProcessor\HtmlPruner;
 
-class HTML {
+class StyleInliner {
 
-    public static function style_inline( $content, $styles = '' ) {
+    public static function inline( string $content, string $styles = '' ): string {
         if ( class_exists( 'DOMDocument' ) ) {
             try {
                 $css_inliner  = CssInliner::fromHtml( $content )->inlineCss( $styles );
@@ -21,10 +21,21 @@ class HTML {
                 error_log( $e->getMessage() );
             }
         } else {
-            $content = '<style type="text/css">' . strip_tags( $styles ) . '</style>' . $content;
+            $content = '<style>' . strip_tags( $styles ) . '</style>' . $content;
         }
 
         return $content;
     }
 
+    /**
+     * @return array|string|string[]
+     */
+    protected function replace_placeholders( string $string ): string {
+        if ( empty( $this->placeholders ) ) {
+            return $string;
+        }
+
+        return (string) str_replace( array_keys( $this->placeholders ), array_values( $this->placeholders ), $string );
+    }
+
 }
diff --git a/src/Mailer.php b/src/Mailer.php
deleted file mode 100644
index be4ce751772fbfd2040a7c5148c2b53768860779..0000000000000000000000000000000000000000
--- a/src/Mailer.php
+++ /dev/null
@@ -1,216 +0,0 @@
-<?php
-
-namespace WPDesk\Library\WPEmail;
-
-use Exception;
-use WP_Error;
-use WPDesk\Library\WPEmail\Abstracts\EmailInterface;
-use WPDesk\Library\WPEmail\Helpers\HTML;
-use WPDesk\View\Renderer\Renderer;
-use WPDesk\View\Renderer\SimplePhpRenderer;
-use WPDesk\View\Resolver\ChainResolver;
-use WPDesk\View\Resolver\DirResolver;
-
-class Mailer {
-
-    /**
-     * @var EmailInterface[]
-     */
-    private $emails = [];
-
-    /**
-     * @var Renderer
-     */
-    private $renderer;
-
-    /**
-     * @var array
-     */
-    private $template_attributes;
-
-    /**
-     * @var string
-     */
-    private $from;
-
-    /**
-     * @var string
-     */
-    private $from_name;
-
-    /**
-     * @param array $dirs
-     * @param array $template_attributes
-     */
-    public function __construct(
-        array $dirs = [],
-        array $template_attributes = []
-    ) {
-        $this->template_attributes = $template_attributes;
-        $this->set_renderer( $this->init_renderer( $dirs ) );
-        $this->set_from( get_bloginfo( 'admin_email' ) );
-        $this->set_from_name( get_bloginfo( 'name', 'display' ) );
-    }
-
-    /**
-     * @param array $dirs
-     *
-     * @return Renderer
-     */
-    private function init_renderer( array $dirs = [] ): Renderer {
-        $resolver = new ChainResolver();
-        foreach ( $dirs as $dir ) {
-            $resolver->appendResolver( new DirResolver( $dir ) );
-        }
-        $resolver->appendResolver( new DirResolver( dirname( __DIR__ ) . '/templates' ) );
-
-        return new SimplePhpRenderer( $resolver );
-    }
-
-    /**
-     * @param Renderer $renderer
-     *
-     * @return void
-     */
-    public function set_renderer( Renderer $renderer ) {
-        $this->renderer = $renderer;
-    }
-
-    /**
-     * @param EmailInterface $email
-     *
-     * @return void
-     */
-    public function add_email( EmailInterface $email ) {
-        $this->emails[ $email->get_id() ] = $email;
-    }
-
-    /**
-     * @return EmailInterface[]
-     */
-    public function get_emails(): array {
-        return $this->emails;
-    }
-
-    /**
-     * @param string $from
-     *
-     * @return void
-     */
-    public function set_from( string $from ) {
-        $this->from = $from;
-    }
-
-    /**
-     * @return string
-     */
-    public function get_from(): string {
-        return $this->from;
-    }
-
-    /**
-     * @param string $from_name
-     *
-     * @return void
-     */
-    public function set_from_name( string $from_name ) {
-        $this->from_name = $from_name;
-    }
-
-    /**
-     * @return string
-     */
-    public function get_from_name(): string {
-        return $this->from_name;
-    }
-
-    /** @return void */
-    public function send( $include = [] ) {
-        foreach ( $this->get_emails() as $email ) {
-            if ( ! empty( $include ) && ! in_array( $email->get_id(), $include, true ) ) {
-                continue;
-            }
-            if ( $email->get_is_enable() ) {
-                $mailer_from = $this->get_from();
-                add_filter(
-                    'wp_mail_from',
-                    $from_cb = static function ( $from ) use ( $mailer_from ) {
-                        return $mailer_from;
-                    }
-                );
-
-                $mailer_from_name = $this->get_from_name();
-                add_filter(
-                    'wp_mail_from_name',
-                    $from_name_cb = static function ( $from_name ) use ( $mailer_from_name ) {
-                        return $mailer_from_name;
-                    }
-                );
-                add_action( 'wp_mail_failed', [ $this, 'catch_error' ] );
-
-                try {
-                    $success = wp_mail(
-                        $email->get_recipients(),
-                        $email->get_subject(),
-                        $this->get_email_template( $email ),
-                        $email->get_headers(),
-                        $email->get_attachments()
-                    );
-                    if ( ! $success ) {
-                        throw new MailerException( 'Count not send the mail with wp_mail()' );
-                    }
-                } catch ( Exception $e ) {
-                    if ( $e instanceof MailerException ) {
-                        throw $e;
-                    }
-
-                    throw new MailerException( sprintf( 'wp_mail() failure. Original error: %s', $e->getMessage() ), 0, $e );
-                } finally {
-                    remove_action( 'wp_mail_failed', [ $this, 'catch_error' ], 99999 );
-                    remove_filter( 'wp_mail_from', $from_cb );
-                    remove_filter( 'wp_mail_from_name', $from_name_cb );
-                }
-            }
-        }
-
-    }
-
-    /** @return void */
-    public function catch_error( WP_Error $error ) {
-        throw MailerException::with_wp_error( $error );
-    }
-
-    protected function get_email_template( EmailInterface $email ): string {
-        $output = $this->renderer->render(
-            'html/email-header',
-            [
-                'heading' => $this->template_attributes['heading'] ?? $email->get_heading(),
-                'logo'    => $this->template_attributes['logo']
-            ]
-        );
-        $output .= $this->renderer->render( 'html/' . $email->get_id(), [ 'content' => $email->get_content() ] );
-        $output .= $this->renderer->render( 'html/email-footer', [ 'footer' => $this->template_attributes['footer'] ] );
-
-        return $this->css_inline( $output );
-    }
-
-    /**
-     * @param string $content
-     *
-     * @return mixed|string
-     */
-    protected function css_inline( string $content ): string {
-        $styles = $this->renderer->render(
-            'html/email-styles',
-            [
-                'primary' => $this->template_attributes['primary'] ?? '#d15291',
-                'text'    => $this->template_attributes['text'] ?? '#303030',
-                'bg'      => $this->template_attributes['bg'] ?? '#f9f9f9',
-                'body'    => $this->template_attributes['body'] ?? '#ffffff',
-            ]
-        );
-
-        return HTML::style_inline( $content, $styles );
-    }
-
-}
diff --git a/src/Template.php b/src/Template.php
new file mode 100644
index 0000000000000000000000000000000000000000..c0c66bac330d0f71b66e69ed4a8d03f94b97eab2
--- /dev/null
+++ b/src/Template.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace WPDesk\Library\WPEmail;
+
+use WPDesk\Library\WPEmail\Helpers\StyleInliner;
+use WPDesk\View\Renderer\Renderer;
+
+class Template {
+
+    /**
+     * @var Renderer
+     */
+    private $renderer;
+
+    /**
+     * @var array
+     */
+    private $template_attributes;
+
+    public function __construct( Renderer $renderer, array $template_attributes ) {
+        $this->renderer            = $renderer;
+        $this->template_attributes = wp_parse_args( $template_attributes, $this->get_default_template_attributes() );
+    }
+
+    public function get_body( string $content ): string {
+        $output = $this->renderer->render( 'html/email-header', $this->template_attributes );
+        $output .= $this->renderer->render( 'html/email-content', [ 'content' => $content ] );
+        $output .= $this->renderer->render( 'html/email-footer', [ 'footer' => $this->template_attributes['footer'] ] );
+
+        return $this->css_inline( $output );
+    }
+
+    /**
+     * @param string $content
+     *
+     * @return mixed|string
+     */
+    public function css_inline( string $content ): string {
+        $styles = $this->renderer->render( 'html/email-styles', $this->template_attributes );
+
+        return StyleInliner::inline( $content, $styles );
+    }
+
+    public function get_default_template_attributes(): array {
+        return [
+            'heading' => '',
+            'logo'    => '',
+            'footer'  => '',
+            'primary' => '#d15291',
+            'text'    => '#303030',
+            'bg'      => '#f9f9f9',
+            'body'    => '#ffffff',
+        ];
+    }
+
+}
diff --git a/src/WPMailer.php b/src/WPMailer.php
new file mode 100644
index 0000000000000000000000000000000000000000..9097fc757c20f9c4be16808d4d7d382b49a21ae1
--- /dev/null
+++ b/src/WPMailer.php
@@ -0,0 +1,87 @@
+<?php
+
+namespace WPDesk\Library\WPEmail;
+
+use Exception;
+use WP_Error;
+use WPDesk\Library\WPEmail\Abstracts\Email;
+use WPDesk\Library\WPEmail\Abstracts\Mailer;
+use WPDesk\Library\WPEmail\Exceptions\MailerException;
+use WPDesk\View\Renderer\Renderer;
+use WPDesk\View\Renderer\SimplePhpRenderer;
+use WPDesk\View\Resolver\ChainResolver;
+use WPDesk\View\Resolver\DirResolver;
+
+class WPMailer implements Mailer {
+
+    /**
+     * @var Renderer
+     */
+    private $renderer;
+
+    public function __construct() {
+        $resolver = new ChainResolver();
+        $resolver->appendResolver( new DirResolver( __DIR__ . '/templates' ) );
+        $renderer = new SimplePhpRenderer( $resolver );
+        $this->set_renderer( $renderer );
+    }
+
+    public function set_renderer( Renderer $renderer ) {
+        $this->renderer = $renderer;
+    }
+
+    public function get_renderer(): Renderer {
+        return $this->renderer;
+    }
+
+    /** @return void */
+    public function send( Email $email ): void {
+        $mailer_from = $email->get_from();
+        add_filter(
+            'wp_mail_from',
+            $from_cb = static function ( $from ) use ( $mailer_from ) {
+                return $mailer_from;
+            }
+        );
+
+        $mailer_from_name = $email->get_from_name();
+        add_filter(
+            'wp_mail_from_name',
+            $from_name_cb = static function ( $from_name ) use ( $mailer_from_name ) {
+                return $mailer_from_name;
+            }
+        );
+        add_action( 'wp_mail_failed', [ $this, 'catch_error' ] );
+
+        $email_template = new Template( $this->renderer, $email->get_template_attributes() );
+
+        try {
+            $success = wp_mail(
+                $email->get_recipients(),
+                $email->get_subject(),
+                $email_template->get_body( $email->get_content() ),
+                $email->get_headers(),
+                $email->get_attachments()
+            );
+            if ( ! $success ) {
+                throw new MailerException( 'Count not send the mail with wp_mail()' );
+            }
+        } catch ( Exception $e ) {
+            if ( $e instanceof MailerException ) {
+                throw $e;
+            }
+
+            throw new MailerException( sprintf( 'wp_mail() failure. Original error: %s', $e->getMessage() ), 0, $e );
+        } finally {
+            remove_action( 'wp_mail_failed', [ $this, 'catch_error' ], 99999 );
+            remove_filter( 'wp_mail_from', $from_cb );
+            remove_filter( 'wp_mail_from_name', $from_name_cb );
+        }
+    }
+
+    /** @return void */
+    public function catch_error( WP_Error $error ) {
+        throw MailerException::with_wp_error( $error );
+    }
+
+}
diff --git a/templates/html/default.php b/templates/html/email-content.php
similarity index 100%
rename from templates/html/default.php
rename to templates/html/email-content.php
diff --git a/templates/html/email-footer.php b/templates/html/email-footer.php
index e5aab55503c0b7d692076e03de17219f28fc689f..c6b9aeaea464d764893c196bb12de68cf7d6be44 100644
--- a/templates/html/email-footer.php
+++ b/templates/html/email-footer.php
@@ -1,18 +1,6 @@
 <?php
 /**
  * Email Footer
- *
- * This template can be overridden by copying it to yourtheme/woocommerce/emails/email-footer.php.
- *
- * HOWEVER, on occasion WooCommerce will need to update template files and you
- * (the theme developer) will need to copy the new files to your theme to
- * maintain compatibility. We try to do this as little as possible, but it does
- * happen. When this occurs the version of the template file will be bumped and
- * the readme will list any important changes.
- *
- * @see https://docs.woocommerce.com/document/template-structure/
- * @package WooCommerce\Templates\Emails
- * @version 3.7.0
  */
 
 defined( 'ABSPATH' ) || exit;
diff --git a/templates/html/email-header.php b/templates/html/email-header.php
index d73b5a0f780ba83a7e1a9f7db3c8c11a840da03f..10b8088fd6d6640e3976474918f1899da872c530 100644
--- a/templates/html/email-header.php
+++ b/templates/html/email-header.php
@@ -1,18 +1,6 @@
 <?php
 /**
  * Email Header
- *
- * This template can be overridden by copying it to yourtheme/woocommerce/emails/email-header.php.
- *
- * HOWEVER, on occasion WooCommerce will need to update template files and you
- * (the theme developer) will need to copy the new files to your theme to
- * maintain compatibility. We try to do this as little as possible, but it does
- * happen. When this occurs the version of the template file will be bumped and
- * the readme will list any important changes.
- *
- * @see     https://docs.woocommerce.com/document/template-structure/
- * @package WooCommerce\Templates\Emails
- * @version 4.0.0
  */
 
 if ( ! defined( 'ABSPATH' ) ) {
diff --git a/templates/html/email-styles.php b/templates/html/email-styles.php
index 2fae35bd616851f16ea1ebf68ec8d228de5ff00c..5a204dc46b4f59fb70e272bd8733879c982db83f 100644
--- a/templates/html/email-styles.php
+++ b/templates/html/email-styles.php
@@ -1,6 +1,6 @@
 <?php
 
-use WPDesk\Library\WPEmail\Helpers\Template;
+use WPDesk\Library\WPEmail\Helpers\ColorConversion;
 
 $params = isset( $params ) ? $params : [];
 
@@ -12,22 +12,22 @@ if ( ! defined( 'ABSPATH' ) ) {
 $bg        = $params['bg'] ?? '#f8f8f8';
 $body      = $params['body'] ?? '#ffffff';
 $base      = $params['primary'] ?? '#5c9a2c';
-$base_text = Template::light_or_dark( $base, '#171717', '#ffffff' );
+$base_text = ColorConversion::light_or_dark( $base, '#171717', '#ffffff' );
 $text      = $params['text'] ?? '#33333';
 
 // Pick a contrasting color for links.
-$link_color = Template::is_hex_light( $base ) ? $base : $base_text;
+$link_color = ColorConversion::is_hex_light( $base ) ? $base : $base_text;
 
-if ( Template::is_hex_light( $body ) ) {
-    $link_color = Template::is_hex_light( $base ) ? $base_text : $base;
+if ( ColorConversion::is_hex_light( $body ) ) {
+    $link_color = ColorConversion::is_hex_light( $base ) ? $base_text : $base;
 }
 
-$bg_darker_10    = Template::hex_darker( $bg, 10 );
-$body_darker_10  = Template::hex_darker( $body, 10 );
-$base_lighter_20 = Template::hex_lighter( $base, 20 );
-$base_lighter_40 = Template::hex_lighter( $base, 40 );
-$text_lighter_20 = Template::hex_lighter( $text, 20 );
-$text_lighter_40 = Template::hex_lighter( $text, 40 );
+$bg_darker_10    = ColorConversion::hex_darker( $bg, 10 );
+$body_darker_10  = ColorConversion::hex_darker( $body, 10 );
+$base_lighter_20 = ColorConversion::hex_lighter( $base, 20 );
+$base_lighter_40 = ColorConversion::hex_lighter( $base, 40 );
+$text_lighter_20 = ColorConversion::hex_lighter( $text, 20 );
+$text_lighter_40 = ColorConversion::hex_lighter( $text, 40 );
 
 // !important; is a gmail hack to prevent styles being stripped if it doesn't like something.
 // body{padding: 0;} ensures proper scale/positioning of the email in the iOS native email app.
diff --git a/templates/plain/default.php b/templates/plain/email-content.php
similarity index 100%
rename from templates/plain/default.php
rename to templates/plain/email-content.php
diff --git a/tests/unit/Mailer/ColorTest.php b/tests/unit/Mailer/ColorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..940c1b7929923abfff2dc6c915dee38f942e6721
--- /dev/null
+++ b/tests/unit/Mailer/ColorTest.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace Tests\Mailer;
+
+use PHPUnit\Framework\TestCase;
+use WPDesk\Library\WPEmail\Helpers\ColorConversion;
+
+class ColorTest extends TestCase {
+
+    public function testShouldCheckHexConversion() {
+        $white_hex = ColorConversion::rgb_from_hex( '#FFFFFF' );
+        $white_rgb = [
+            'R' => 255,
+            'G' => 255,
+            'B' => 255,
+        ];
+        $this->assertSame( $white_hex, $white_rgb );
+
+        $black_hex = ColorConversion::rgb_from_hex( '#000000' );
+        $black_rgb = [
+            'R' => 0,
+            'G' => 0,
+            'B' => 0,
+        ];
+        $this->assertSame( $black_hex, $black_rgb );
+    }
+
+
+    public function testShouldCheckIsHexIsDarker() {
+        $dark_hex = ColorConversion::is_hex_light( '#333333' );
+        $this->assertFalse( $dark_hex );
+    }
+
+
+    public function testShouldCheckIsHexIsLighter() {
+        $light_hex = ColorConversion::is_hex_light( '#f8f8f8' );
+        $this->assertTrue( $light_hex );
+    }
+
+    public function testShouldMakeColorDarker() {
+        $dark_hex = ColorConversion::hex_darker( '#f8f8f8' );
+        $this->assertSame( $dark_hex, '#aeaeae' );
+    }
+
+
+    public function testShouldMakeColorLighter() {
+        $light_hex = ColorConversion::hex_lighter( '#f8f8f8' );
+        $this->assertSame( $light_hex, '#fafafa' );
+    }
+
+}
diff --git a/tests/unit/Mailer/MailTest.php b/tests/unit/Mailer/MailTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..5397f3adcfed201559086f208a4a1d3ea21f0a01
--- /dev/null
+++ b/tests/unit/Mailer/MailTest.php
@@ -0,0 +1,87 @@
+<?php
+
+namespace Tests\Mailer;
+
+use PHPUnit\Framework\TestCase;
+use WPDesk\Library\WPEmail\Abstracts\Email;
+
+class MailTest extends TestCase {
+
+    const FROM = 'anna.nowak@gmail.com';
+    const FROM_NAME = 'Anna Nowak';
+    const RECIPIENTS = [ 'jan.nowak@gmail.com' ];
+    const SUBJECT = 'Some Subject';
+    const CONTENT = 'Lorem ipsum';
+
+    public $email;
+
+    public function setUp(): void {
+        parent::setUp();
+        \WP_Mock::setUp();
+        $this->email = new Email();
+    }
+
+    public function testSetAndGetFromEmail(): void {
+        $data = \WP_Mock::userFunction('sanitize_email')->andReturn('');
+        print_r( $data );
+        exit;
+        \WP_Mock::passthruFunction( 'sanitize_email' );
+        $this->email->set_from( 'john@example.com' );
+        $this->assertEquals( 'john@example.com', $this->email->get_from() );
+    }
+
+    public function testSetAndGetFromName(): void {
+        \WP_Mock::passthruFunction( 'wp_specialchars_decode' );
+        $this->email->set_from_name( 'John Doe' );
+        $this->assertEquals( 'John Doe', $this->email->get_from_name() );
+    }
+
+    public function testSetAndGetSubject(): void {
+        $this->email->set_subject( 'Hello World' );
+        $this->assertEquals( 'Hello World', $this->email->get_subject() );
+    }
+
+    public function testSetAndGetRecipients(): void {
+        $this->email->set_recipients( [ 'jane@example.com', 'mark@example.com' ] );
+        $this->assertEquals( [ 'jane@example.com', 'mark@example.com' ], $this->email->get_recipients() );
+    }
+
+    public function testSetAndGetHeader(): void {
+        $this->email->set_header( 'Return-Path', 'mail@testsite.com' );
+        $this->assertEquals( 'mail@testsite.com', $this->email->get_header( 'Return-Path' ) );
+    }
+
+    public function testSetAndGetAttachments(): void {
+        $this->email->set_attachments( [ 'file1.txt', 'file2.jpg' ] );
+        $this->assertEquals( [ 'file1.txt', 'file2.jpg' ], $this->email->get_attachments() );
+    }
+
+    public function testIsHtml(): void {
+        $this->email->set_content_type();
+        $this->assertTrue( $this->email->is_html() );
+
+        $this->email->set_content_type( 'plain' );
+        $this->assertFalse( $this->email->is_html() );
+    }
+
+    public function testSetAndGetContentType(): void {
+        $this->email->set_content_type( 'html' );
+        $this->assertEquals( 'text/html', $this->email->get_header( 'Content-Type' ) );
+
+        $this->email->set_content_type( 'plain' );
+        $this->assertEquals( 'text/plain', $this->email->get_header( 'Content-Type' ) );
+
+        $this->email->set_content_type( 'multipart' );
+        $this->assertEquals( 'multipart/alternative', $this->email->get_header( 'Content-Type' ) );
+    }
+
+    public function testSetAndGetContent(): void {
+        $this->email->set_content( 'Hello World' );
+        $this->assertEquals( 'Hello World', $this->email->get_content() );
+    }
+
+    public function tearDown(): void {
+        \WP_Mock::tearDown();
+    }
+
+}
diff --git a/tests/unit/bootstrap.php b/tests/unit/bootstrap.php
index 76b8109582ae17560b77a6e0499b232e09047810..38a4eb0d02d4281e3ff45d89ea6ee201737e2750 100644
--- a/tests/unit/bootstrap.php
+++ b/tests/unit/bootstrap.php
@@ -5,5 +5,22 @@
 
 require_once __DIR__ . '/../../vendor/autoload.php';
 
+error_reporting( E_ALL );
+
+if ( getenv( 'PLUGIN_PATH' ) !== false ) {
+    define( 'PLUGIN_PATH', getenv( 'PLUGIN_PATH' ) );
+} else {
+    define( 'PLUGIN_PATH', __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR );
+}
+
+if ( getenv( 'ABSPATH' ) !== false ) {
+    define( 'ABSPATH', getenv( 'ABSPATH' ) );
+} else {
+    define( 'ABSPATH', PLUGIN_PATH . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR );
+}
+
 WP_Mock::setUsePatchwork( true );
 WP_Mock::bootstrap();
+
+
+