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/lang/pl_PL.po b/lang/pl_PL.po
new file mode 100644
index 0000000000000000000000000000000000000000..b385208d0f537f4fb33c4267bf4f4bc2c6980a3a
--- /dev/null
+++ b/lang/pl_PL.po
@@ -0,0 +1,357 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: Plugin Template\n"
+"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/flexible-"
+"donation\n"
+"POT-Creation-Date: 2023-02-02 09:05+0100\n"
+"PO-Revision-Date: 2023-02-02 09:05+0100\n"
+"Last-Translator: Krzysztof Dyszczyk <krzysztof.dyszczyk@gmail.com>\n"
+"Language-Team: Polish\n"
+"Language: pl_PL\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10 >= 2 && n%10<=4 &&(n"
+"%100<10||n%100 >= 20)? 1 : 2);\n"
+"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
+"|| n%100>=20) ? 1 : 2);\n"
+"X-Generator: Poedit 3.2.2\n"
+"X-Loco-Version: 2.3.0; wp-5.2.2X-Poedit-Basepath: ..\n"
+"X-Poedit-SourceCharset: UTF-8\n"
+"X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;"
+"esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;"
+"_nx_noop:3c,1,2;__ngettext_noop:1,2\n"
+"X-Poedit-Basepath: ..\n"
+"X-Poedit-SearchPath-0: .\n"
+"X-Poedit-SearchPathExcluded-0: *.js\n"
+"X-Poedit-SearchPathExcluded-1: vendor\n"
+"X-Poedit-SearchPathExcluded-2: vendor_prefixed\n"
+
+#~ msgid "Flexible Donation"
+#~ msgstr "Elastyczne Darowizny"
+
+#~ msgid "Create a donation form in conjunction with popular payment gateways"
+#~ msgstr ""
+#~ "Utwórz formularz darowizny w połączeniu z popularnymi bramkami płatności"
+
+#~ msgid "Settings"
+#~ msgstr "Ustawienia"
+
+#~ msgid "Support"
+#~ msgstr "Wsparcie"
+
+#~ msgid "Amount"
+#~ msgstr "Kwota"
+
+#~ msgid "Payment status"
+#~ msgstr "Status płatności"
+
+#~ msgid "Payment method"
+#~ msgstr "Metoda płatności"
+
+#~ msgid "Form"
+#~ msgstr "Formularz"
+
+#~ msgid "%s PLN"
+#~ msgstr "%s PLN"
+
+#~ msgid "Unknown"
+#~ msgstr "Nieznany"
+
+#~ msgid "Donation data"
+#~ msgstr "Dane darowizny"
+
+#~ msgid "Form settings"
+#~ msgstr "Ustawienia formularza"
+
+#~ msgid "I accept terms & conditions"
+#~ msgstr "AkceptujÄ™ regulamin darowizn"
+
+#~ msgid "First name"
+#~ msgstr "ImiÄ™"
+
+#~ msgid "Last name"
+#~ msgstr "Nazwisko"
+
+#~ msgid "E-mail"
+#~ msgstr "E-mail"
+
+#~ msgid "Comment"
+#~ msgstr "Komentarz"
+
+#~ msgid "Terms"
+#~ msgstr "Regulamin"
+
+#~ msgid "Send donation"
+#~ msgstr "Wyślij darowiznę"
+
+#~ msgid "terms & conditions"
+#~ msgstr "regulamin"
+
+#~ msgid "Bank transfer"
+#~ msgstr "Przelew bankowy"
+
+#~ msgid "Bank Transfer Settings"
+#~ msgstr "Ustawienia przelewu bankowego"
+
+#~ msgid "Recipient data"
+#~ msgstr "Dane odbiorcy"
+
+#~ msgid "Company name, street, street number, post code, city etc."
+#~ msgstr "Nazwa firmy, ulica, numer ulicy, kod pocztowy, miasto itp."
+
+#~ msgid "Account number"
+#~ msgstr "Nr konta"
+
+#~ msgid "Bank name"
+#~ msgstr "Nazwa banku"
+
+#~ msgid "Payment title"
+#~ msgstr "Tytuł płatności"
+
+#~ msgid "SWIFT"
+#~ msgstr "SWIFT"
+
+#~ msgid "Sort code"
+#~ msgstr "Sort code"
+
+#~ msgid "Description"
+#~ msgstr "Opis"
+
+#~ msgid ""
+#~ "Please pay directly to our bank account. Please use defined payment title "
+#~ "as the payment title. Your order will be processed after the payment is "
+#~ "credited to our account."
+#~ msgstr ""
+#~ "Prosimy o wpłatę bezpośrednio na nasze konto bankowe. Jako tytuł "
+#~ "płatności proszę użyć numeru zamówienia. Twoje zamówienie zostanie "
+#~ "zrealizowane po zaksięgowaniu wpłaty na naszym koncie."
+
+#~ msgid "PayU"
+#~ msgstr "PayU"
+
+#~ msgid "Niepoprawne zamówienie PayU!"
+#~ msgstr "Niepoprawne zamówienie PayU!"
+
+#~ msgid "Payu Settings"
+#~ msgstr "Ustawienia PayU"
+
+#~ msgid "POS ID"
+#~ msgstr "POS ID"
+
+#~ msgid "MD5"
+#~ msgstr "MD5"
+
+#~ msgid "Client ID"
+#~ msgstr "Client ID"
+
+#~ msgid "Client secret"
+#~ msgstr "Client secret"
+
+#~ msgid "Currency"
+#~ msgstr "Waluta"
+
+#~ msgid "Is sandbox"
+#~ msgstr "Włącz sanbox"
+
+#~ msgid "%1$s, Darowizna %2$s"
+#~ msgstr "%1$s, Darowizna %2$s"
+
+#~ msgid "Darowizna nr %s"
+#~ msgstr "Darowizna nr %s"
+
+#~ msgid "Donations"
+#~ msgstr "Darowizny"
+
+#~ msgid "Donation"
+#~ msgstr "Darowizna"
+
+#~ msgid "Not donations found."
+#~ msgstr "Nie znaleziono darowizn."
+
+#~ msgid "Forms"
+#~ msgstr "Formularze"
+
+#~ msgid "Not forms found."
+#~ msgstr "Nie znaleziono formularzy."
+
+#~ msgid "Donation Summary"
+#~ msgstr "Podsumowanie Darowizny"
+
+#~ msgid "Pending"
+#~ msgstr "OczekujÄ…cy"
+
+#~ msgid "Completed"
+#~ msgstr "Opłacone"
+
+#~ msgid "Failed"
+#~ msgstr "Anulowane"
+
+#~ msgid "Save Changes"
+#~ msgstr "Zapisz zmiany"
+
+#~ msgid "Summary Page"
+#~ msgstr "Strona podsumowania"
+
+#~ msgid "Select or create summary page."
+#~ msgstr "Wybierz stronÄ™ podsumowania."
+
+#~ msgid "Summary Page Content"
+#~ msgstr "Treść strony podsumowania"
+
+#~ msgid "This content will be displayed on summary page."
+#~ msgstr "Ta treść pojawi się na stronie podsumowania."
+
+#~ msgid "Customer e-mail"
+#~ msgstr "E-mail darczyńcy"
+
+#~ msgid "Enable"
+#~ msgstr "Włącz"
+
+#~ msgid "Subject"
+#~ msgstr "Temat"
+
+#~ msgid "[{site_title}]: Your donation has been made"
+#~ msgstr "[{site_title}]: Twoja darowizna została przekazana"
+
+#~ msgid "Email heading"
+#~ msgstr "Nagłówek maila"
+
+#~ msgid "Thank you for donating"
+#~ msgstr "Dziękujemy za darowiznę"
+
+#~ msgid "Email body"
+#~ msgstr "Treść maila"
+
+#~ msgid ""
+#~ "Hi {donation_first_name},<br/><br/>Thank you for your donation of "
+#~ "£{donation_amount}.<br/><br/>{donate_summary_table}"
+#~ msgstr ""
+#~ "Cześć {donation_first_name},<br/><br/>Dziękujemy za darowiznę w kwocie "
+#~ "{donation_amount}zł.<br/><br/>{donate_summary_table}"
+
+#~ msgid "Admin e-mail"
+#~ msgstr "E-mail administratora"
+
+#~ msgid ""
+#~ "Hi Admin,<br/><br/>A new donation in the amount of £{donation_amount} has "
+#~ "been received.<br/><br/>You can check the details <a href="
+#~ "\"{donation_url}\">here</a>.<br/><br/>{donation_summary_table}"
+#~ msgstr ""
+#~ "Cześć Admin,<br/><br/>Nowa darowizna w kwocie {donation_amount}zł została "
+#~ "przekazana.<br/><br/>Sprawdź szczegóły <a href=\"{donation_url}\">tutaj</"
+#~ "a>.<br/><br/>{donation_summary_table}"
+
+#~ msgid "User Price"
+#~ msgstr "Kwota użytkownika"
+
+#~ msgid "Minimum price:"
+#~ msgstr "Kwota minimalna:"
+
+#~ msgid "Preset Prices"
+#~ msgstr "Zdefiniowane ceny"
+
+#~ msgid "Add item"
+#~ msgstr "Dodaj wartość"
+
+#~ msgid "Remove item"
+#~ msgstr "Usuń wartość"
+
+#~ msgid "Terms and Conditions"
+#~ msgstr "Regulamin"
+
+#~ msgid "Show terms and conditions"
+#~ msgstr "Pokaż regulamin użytkownika"
+
+#~ msgid "Link label:"
+#~ msgstr "Etykieta linku:"
+
+#~ msgid "Terms page:"
+#~ msgstr "Strona z warunkami:"
+
+#~ msgid "Payment methods"
+#~ msgstr "Metody płatności"
+
+#~ msgid "First name:"
+#~ msgstr "ImiÄ™:"
+
+#~ msgid "Last name:"
+#~ msgstr "Nazwisko:"
+
+#~ msgid "E-mail:"
+#~ msgstr "E-mail:"
+
+#~ msgid "Amount:"
+#~ msgstr "Kwota:"
+
+#~ msgid "Comment:"
+#~ msgstr "Komentarz:"
+
+#~ msgid "Payment method:"
+#~ msgstr "Metoda płatności:"
+
+#~ msgid "Payment status:"
+#~ msgstr "Status płatności:"
+
+#~ msgid "Sort Code"
+#~ msgstr "Sort Code"
+
+#~ msgid "Donation details"
+#~ msgstr "Szczegóły darowizny"
+
+#~ msgid "Thank You Page"
+#~ msgstr "Strona podziękowania"
+
+#~ msgid "Minimum amount"
+#~ msgstr "Minimalna kwota"
+
+#~ msgid "Set minimum amount. Default: 1."
+#~ msgstr "Ustaw kwotę minimalną. Domyślnie 10."
+
+#~ msgid "Maximum amount"
+#~ msgstr "Maksymalna kwota"
+
+#~ msgid "Set maximum amount or leave empty."
+#~ msgstr "Ustaw kwotÄ™ maksymalnÄ… lub pozostaw puste."
+
+#~ msgid "Purposes"
+#~ msgstr "Cele"
+
+#~ msgid "Purpose"
+#~ msgstr "Cek"
+
+#~ msgid "Search Purpose"
+#~ msgstr "Szukaj celu"
+
+#~ msgid "Popular Purposes"
+#~ msgstr "Popularne cele"
+
+#~ msgid "All Purposes"
+#~ msgstr "Wszystki cele"
+
+#~ msgid "Edit Purposes"
+#~ msgstr "Edytuj cel"
+
+#~ msgid "Update Purposes"
+#~ msgstr "Aktualizuj cel"
+
+#~ msgid "Add New Purposes"
+#~ msgstr "Dodaj nowy cel"
+
+#~ msgid "New Purpose Name"
+#~ msgstr "Nazwa celu"
+
+#~ msgid "Add or remove purposes"
+#~ msgstr "Dodaj lub usuń cele"
+
+#~ msgid "Choose from the most used purposes"
+#~ msgstr "Wybierz jeden z najczęściej używanych celów"
+
+#~ msgid "No purposes found."
+#~ msgstr "Nie znaleziono celów."
+
+#~ msgid "Enable email."
+#~ msgstr "Włącz powiadomienie."
+
+#~ msgid "Define prices:"
+#~ msgstr "Zdefiniuj ceny"
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/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 5aba38c803aee18da6a6a7df37bbbf178e5f4e80..0000000000000000000000000000000000000000
--- a/src/Abstracts/EmailAbstract.php
+++ /dev/null
@@ -1,122 +0,0 @@
-<?php
-
-namespace WPDesk\Library\WPEmail\Abstracts;
-
-use WPDesk\View\Renderer\Renderer;
-
-abstract class EmailAbstract implements EmailInterface {
-
-    /**
-     * @var Renderer
-     */
-    private $renderer;
-
-    public function __construct( Renderer $renderer, array $recipients ) {
-        $this->renderer   = $renderer;
-        $this->recipients = $recipients;
-    }
-
-    /**
-     * Define unique email ID.
-     *
-     * @return string
-     */
-    abstract public function get_id(): string;
-
-    /**
-     * Get defined placeholders.
-     *
-     * @return string[]
-     */
-    public function get_placeholders(): array {
-        return [];
-    }
-
-    /**
-     * Get email subject.
-     *
-     * @return string
-     */
-    public function get_subject(): string {
-        if ( ! $this->subject ) {
-            throw new \Exception( 'Empty email subject' );
-        }
-
-        return '';
-    }
-
-    /**
-     * Get email heading.
-     *
-     * @return string
-     */
-    public function get_heading(): string {
-        return '';
-    }
-
-    /**
-     * Get valid recipients.
-     *
-     * @return string[]
-     */
-    public function get_recipients(): array {
-        return $this->recipients;
-    }
-
-    /**
-     * Get email headers.
-     *
-     * @return string[]
-     */
-    public function get_headers(): array {
-        return [];
-    }
-
-    /**
-     * Get email attachments.
-     *
-     * @return array
-     */
-    public function get_attachments(): array {
-        return [];
-    }
-
-    /**
-     * Get email type.
-     *
-     * @return string
-     */
-    public function get_type(): string {
-        return 'text/html';
-    }
-
-    /**
-     * Get email content.
-     *
-     * @return string
-     */
-    public function get_content(): string {
-        if ( ! $this->content ) {
-            throw new \Exception( 'Empty email subject' );
-        }
-
-        return '';
-    }
-
-    /**
-     * @return mixed
-     */
-    public function get_object() {
-        return '';
-    }
-
-    /**
-     * Get email content.
-     *
-     * @return string
-     */
-    public function render(): string {
-        return $this->renderer->render( dirname( __DIR__ ) . '/html/default.php', [ 'content' => $this->get_content(), 'heading' => $this->get_heading(), 'object' => $this->get_object() ] );
-    }
-
-}
diff --git a/src/Abstracts/EmailInterface.php b/src/Abstracts/EmailInterface.php
deleted file mode 100644
index 8439a4472b69b22af289730473a349ea92c62e52..0000000000000000000000000000000000000000
--- a/src/Abstracts/EmailInterface.php
+++ /dev/null
@@ -1,70 +0,0 @@
-<?php
-
-namespace WPDesk\Library\WPEmail\Abstracts;
-
-interface EmailInterface {
-
-    /**
-     * Define unique email ID.
-     *
-     * @return string
-     */
-    public function get_id(): string;
-
-    /**
-     * 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 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/EmailSender.php b/src/EmailSender.php
deleted file mode 100644
index f249ad9c4e4f2d88214480633992db1186942492..0000000000000000000000000000000000000000
--- a/src/EmailSender.php
+++ /dev/null
@@ -1,101 +0,0 @@
-<?php
-
-namespace WPDesk\Library\WPEmail\Emails;
-
-use WPDesk\Library\WPEmail\Abstracts\EmailInterface;
-
-class EmailSender {
-
-    /**
-     * @var EmailInterface[]
-     */
-    private $emails = [];
-
-    /**
-     * @var string
-     */
-    private $from;
-
-    /**
-     * @var string
-     */
-    private $from_name;
-
-    /**
-     * @param $from
-     * @param $from_name
-     */
-    public function __construct( $from = '', $from_name = '' ) {
-        $this->from      = $from;
-        $this->from_name = $from_name;
-    }
-
-    public function add_email( EmailInterface $email ) {
-        $this->emails[ $email->get_id() ] = $email;
-    }
-
-    public function get_emails(): array {
-        return $this->emails;
-    }
-
-    /**
-     * WordPress callback for setting the from email
-     *
-     * @param string $email
-     *
-     * @return string
-     */
-    public function from( $email ) {
-        if ( ! empty( $this->from ) && is_email( $this->from ) ) {
-            $email = $this->from;
-        }
-
-        return $email;
-    }
-
-    /**
-     * WordPress callback for setting the from name
-     *
-     * @param string $name
-     *
-     * @return string
-     */
-    public function from_name( $name ) {
-        if ( ! empty( $this->from_name ) ) {
-            $name = html_entity_decode( sanitize_text_field( $this->from_name ) );
-        }
-
-        return $name;
-    }
-
-    /**
-     * Add filters before fire wp_mail.
-     *
-     * @return void
-     */
-    private function before_wp_mail() {
-        add_filter( 'wp_mail_from', array( $this, 'from' ) );
-        add_filter( 'wp_mail_from_name', array( $this, 'from_name' ) );
-    }
-
-    public function send() {
-        foreach ( $this->get_emails() as $email ) {
-            $this->before_wp_mail();
-            wp_mail(
-                $email->get_recipients(), $email->get_subject(), $email->render(), $email->get_headers(), $email->get_attachments()
-            );
-            $this->after_wp_mail();
-        }
-    }
-
-    /**
-     * Remove filters after fire wp_mail.
-     *
-     * @return void
-     */
-    private function after_wp_mail() {
-        remove_filter( 'wp_mail_from', array( $this, 'from' ) );
-        remove_filter( 'wp_mail_from_name', array( $this, 'from_name' ) );
-    }
-
-}
diff --git a/src/Emails/Email.php b/src/Emails/Email.php
deleted file mode 100644
index e5b499128cb50c323db83f3d943df6edfc417d51..0000000000000000000000000000000000000000
--- a/src/Emails/Email.php
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-
-namespace WPDesk\Library\WPEmail\Emails;
-
-use WPDesk\Library\WPEmail\Abstracts\EmailAbstract;
-
-class Email extends EmailAbstract {
-
-    const ID = 'email';
-
-    /**
-     * Define unique email ID.
-     *
-     * @return string
-     */
-    public function get_id(): string {
-        return self::ID;
-    }
-
-}
diff --git a/src/Exceptions/MailerException.php b/src/Exceptions/MailerException.php
new file mode 100644
index 0000000000000000000000000000000000000000..6c005cd4975cdb253742004f5b71ce244db0c1b5
--- /dev/null
+++ b/src/Exceptions/MailerException.php
@@ -0,0 +1,16 @@
+<?php
+
+declare( strict_types=1 );
+
+namespace WPDesk\Library\WPEmail\Exceptions;
+
+class MailerException extends \RuntimeException {
+
+    public static function with_wp_error( \WP_Error $error ): self {
+        $errors  = $error->get_error_messages( 'wp_mail_failed' );
+        $message = implode( "\n", $errors );
+
+        return new self( sprintf( 'wp_mail() failure. Message [%s]', $message ) );
+    }
+}
+
diff --git a/src/Helpers/ColorConversion.php b/src/Helpers/ColorConversion.php
new file mode 100644
index 0000000000000000000000000000000000000000..e8242ee402eaa058e124241c4dbda8d4a13337d5
--- /dev/null
+++ b/src/Helpers/ColorConversion.php
@@ -0,0 +1,125 @@
+<?php
+
+namespace WPDesk\Library\WPEmail\Helpers;
+
+class ColorConversion {
+
+    /**
+     * Determine whether a hex color is light.
+     *
+     * @param mixed $color Color.
+     *
+     * @return bool  True if a light color.
+     */
+    public static function is_hex_light( $color ) {
+        $hex = str_replace( '#', '', $color );
+
+        $c_r = hexdec( substr( $hex, 0, 2 ) );
+        $c_g = hexdec( substr( $hex, 2, 2 ) );
+        $c_b = hexdec( substr( $hex, 4, 2 ) );
+
+        $brightness = ( ( $c_r * 299 ) + ( $c_g * 587 ) + ( $c_b * 114 ) ) / 1000;
+
+        return $brightness > 155;
+    }
+
+    public static function light_or_dark( $color, $dark = '#000000', $light = '#FFFFFF' ) {
+        return self::is_hex_light( $color ) ? $dark : $light;
+    }
+
+
+    /**
+     * Convert RGB to HEX.
+     *
+     * @param mixed $color Color.
+     *
+     * @return array
+     */
+    public static function rgb_from_hex( $color ) {
+        $color = str_replace( '#', '', $color );
+        // Convert shorthand colors to full format, e.g. "FFF" -> "FFFFFF".
+        $color = preg_replace( '~^(.)(.)(.)$~', '$1$1$2$2$3$3', $color );
+
+        $rgb      = [];
+        $rgb['R'] = hexdec( $color[0] . $color[1] );
+        $rgb['G'] = hexdec( $color[2] . $color[3] );
+        $rgb['B'] = hexdec( $color[4] . $color[5] );
+
+        return $rgb;
+    }
+
+
+    /**
+     * Make HEX color darker.
+     *
+     * @param mixed $color  Color.
+     * @param int   $factor Darker factor.
+     *                      Defaults to 30.
+     *
+     * @return string
+     */
+    public static function hex_darker( $color, $factor = 30 ) {
+        $base  = self::rgb_from_hex( $color );
+        $color = '#';
+
+        foreach ( $base as $k => $v ) {
+            $amount      = $v / 100;
+            $amount      = self::round( $amount * $factor );
+            $new_decimal = $v - $amount;
+
+            $new_hex_component = dechex( $new_decimal );
+            if ( strlen( $new_hex_component ) < 2 ) {
+                $new_hex_component = '0' . $new_hex_component;
+            }
+            $color .= $new_hex_component;
+        }
+
+        return $color;
+    }
+
+
+    /**
+     * Make HEX color lighter.
+     *
+     * @param mixed $color  Color.
+     * @param int   $factor Lighter factor.
+     *                      Defaults to 30.
+     *
+     * @return string
+     */
+    public static function hex_lighter( $color, $factor = 30 ) {
+        $base  = self::rgb_from_hex( $color );
+        $color = '#';
+
+        foreach ( $base as $k => $v ) {
+            $amount      = 255 - $v;
+            $amount      = $amount / 100;
+            $amount      = self::round( $amount * $factor );
+            $new_decimal = $v + $amount;
+
+            $new_hex_component = dechex( $new_decimal );
+            if ( strlen( $new_hex_component ) < 2 ) {
+                $new_hex_component = '0' . $new_hex_component;
+            }
+            $color .= $new_hex_component;
+        }
+
+        return $color;
+    }
+
+    /**
+     * @param     $val
+     * @param int $precision
+     * @param int $mode
+     *
+     * @return float
+     */
+    public static function round( $val, int $precision = 0, int $mode = PHP_ROUND_HALF_UP ): float {
+        if ( ! is_numeric( $val ) ) {
+            $val = floatval( $val );
+        }
+
+        return round( $val, $precision, $mode );
+    }
+
+}
diff --git a/src/Helpers/StyleInliner.php b/src/Helpers/StyleInliner.php
new file mode 100644
index 0000000000000000000000000000000000000000..9068deeddfad4b16d4da360d196d05c1035b2ae7
--- /dev/null
+++ b/src/Helpers/StyleInliner.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace WPDesk\Library\WPEmail\Helpers;
+
+use Pelago\Emogrifier\CssInliner;
+use Pelago\Emogrifier\HtmlProcessor\CssToAttributeConverter;
+use Pelago\Emogrifier\HtmlProcessor\HtmlPruner;
+
+class StyleInliner {
+
+    public static function inline( string $content, string $styles = '' ): string {
+        if ( class_exists( 'DOMDocument' ) ) {
+            try {
+                $css_inliner  = CssInliner::fromHtml( $content )->inlineCss( $styles );
+                $dom_document = $css_inliner->getDomDocument();
+                HtmlPruner::fromDomDocument( $dom_document )->removeElementsWithDisplayNone();
+                $content = CssToAttributeConverter::fromDomDocument( $dom_document )
+                                                  ->convertCssToVisualAttributes()
+                                                  ->render();
+            } catch ( \Exception $e ) {
+                error_log( $e->getMessage() );
+            }
+        } else {
+            $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/Integration.php b/src/Integration.php
deleted file mode 100644
index 087e0fe892708d83ca74624d9bdc1fdff7388be6..0000000000000000000000000000000000000000
--- a/src/Integration.php
+++ /dev/null
@@ -1,31 +0,0 @@
-<?php
-
-namespace WPDesk\Library\WPEmail;
-
-use WPDesk\Library\WPEmail\Emails\AdminEmail;
-use WPDesk\Library\WPEmail\Emails\Email;
-use WPDesk\Library\WPEmail\Emails\EmailSender;
-use WPDesk\Persistence\Adapter\WordPress\WordpressOptionsContainer;
-use WPDesk\Persistence\Adapter\WordPress\WordpressTransientContainer;
-use WPDesk\View\Renderer\SimplePhpRenderer;
-use WPDesk\View\Resolver\ChainResolver;
-use WPDesk\View\Resolver\DirResolver;
-use WPDesk\View\Resolver\WPThemeResolver;
-
-class Integration {
-
-    public function __construct() {
-        $chain_resolver = new ChainResolver();
-        $chain_resolver->appendResolver( new WPThemeResolver( 'email_templates' ) );
-        $chain_resolver->appendResolver( new DirResolver( __DIR__ . '/templates' ) );
-        $renderer = new SimplePhpRenderer( $chain_resolver );
-
-        $email_sender = new EmailSender( 'email@mojastron.pl', 'Moj sklep' );
-        $email        = new Email( $renderer, [] );
-
-        $email_sender->add_email( $email );
-        $email_sender->send();
-
-    }
-
-}
diff --git a/src/Parser/HTMLDecorator.php b/src/Parser/HTMLDecorator.php
deleted file mode 100644
index dd6bf5643386b7b71e4ccf715cecd38e42278af3..0000000000000000000000000000000000000000
--- a/src/Parser/HTMLDecorator.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-
-namespace WPDesk\Library\WPEmail\Parser;
-
-class HTMLDecorator {
-
-    public static function style_inline( $content ) {
-        if ( in_array( $this->get_content_type(), array( 'text/html', 'multipart/alternative' ), true ) ) {
-            ob_start();
-            wc_get_template( 'emails/email-styles.php' );
-            $css = apply_filters( 'woocommerce_email_styles', ob_get_clean(), $this );
-
-            $css_inliner_class = \Pelago\Emogrifier\CssInliner::class;
-
-            if ( $this->supports_emogrifier() && class_exists( $css_inliner_class ) ) {
-                try {
-                    $css_inliner = \Pelago\Emogrifier\CssInliner::fromHtml( $content )->inlineCss( $css );
-
-                    do_action( 'woocommerce_emogrifier', $css_inliner, $this );
-
-                    $dom_document = $css_inliner->getDomDocument();
-
-                    HtmlPruner::fromDomDocument( $dom_document )->removeElementsWithDisplayNone();
-                    $content = CssToAttributeConverter::fromDomDocument( $dom_document )
-                                                      ->convertCssToVisualAttributes()
-                                                      ->render();
-                } catch ( Exception $e ) {
-                    $logger = wc_get_logger();
-                    $logger->error( $e->getMessage(), array( 'source' => 'emogrifier' ) );
-                }
-            } else {
-                $content = '<style type="text/css">' . $css . '</style>' . $content;
-            }
-        }
-
-        return $content;
-    }
-
-}
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/src/tempates/html/default.php b/src/tempates/html/default.php
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/tempates/plain/default.php b/src/tempates/plain/default.php
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/templates/html/email-content.php b/templates/html/email-content.php
new file mode 100644
index 0000000000000000000000000000000000000000..f9806149f14c04c3659c766ac675c6acddb3f540
--- /dev/null
+++ b/templates/html/email-content.php
@@ -0,0 +1,6 @@
+<?php
+
+$params = $params ?? [];
+
+?>
+<?php echo wp_kses_post( $params['content'] ); ?>
diff --git a/templates/html/email-footer.php b/templates/html/email-footer.php
new file mode 100644
index 0000000000000000000000000000000000000000..c6b9aeaea464d764893c196bb12de68cf7d6be44
--- /dev/null
+++ b/templates/html/email-footer.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ * Email Footer
+ */
+
+defined( 'ABSPATH' ) || exit;
+?>
+															</div>
+														</td>
+													</tr>
+												</table>
+												<!-- End Content -->
+											</td>
+										</tr>
+									</table>
+									<!-- End Body -->
+								</td>
+							</tr>
+						</table>
+					</td>
+				</tr>
+				<tr>
+					<td align="center" valign="top">
+						<!-- Footer -->
+						<table border="0" cellpadding="10" cellspacing="0" width="600" id="template_footer">
+							<tr>
+								<td valign="top">
+									<table border="0" cellpadding="10" cellspacing="0" width="100%">
+										<tr>
+											<td colspan="2" valign="middle" id="credit">
+												<?php echo $params['footer'] ?? ''; ?>
+											</td>
+										</tr>
+									</table>
+								</td>
+							</tr>
+						</table>
+						<!-- End Footer -->
+					</td>
+				</tr>
+			</table>
+		</div>
+	</body>
+</html>
diff --git a/templates/html/email-header.php b/templates/html/email-header.php
new file mode 100644
index 0000000000000000000000000000000000000000..10b8088fd6d6640e3976474918f1899da872c530
--- /dev/null
+++ b/templates/html/email-header.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Email Header
+ */
+
+if ( ! defined( 'ABSPATH' ) ) {
+    exit; // Exit if accessed directly
+}
+
+$params = isset( $params ) ? $params : [];
+
+?>
+<!DOCTYPE html>
+<html <?php language_attributes(); ?>>
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=<?php bloginfo( 'charset' ); ?>"/>
+    <title><?php echo get_bloginfo( 'name', 'display' ); ?></title>
+</head>
+<body <?php echo is_rtl() ? 'rightmargin' : 'leftmargin'; ?>="0" marginwidth="0" topmargin="0" marginheight="0" offset="0">
+<div id="wrapper" dir="<?php echo is_rtl() ? 'rtl' : 'ltr'; ?>">
+    <table border="0" cellpadding="0" cellspacing="0" height="100%" width="100%">
+        <tr>
+            <td align="center" valign="top">
+                <div id="template_header_image">
+                    <?php
+                    if ( $params['logo'] ) {
+                        echo '<p style="margin-top:0;"><img src="' . esc_url( $params['logo'] ) . '" alt="' . get_bloginfo( 'name', 'display' ) . '" /></p>';
+                    }
+                    ?>
+                </div>
+                <table border="0" cellpadding="0" cellspacing="0" width="600" id="template_container">
+                    <tr>
+                        <td align="center" valign="top">
+                            <!-- Header -->
+                            <table border="0" cellpadding="0" cellspacing="0" width="100%" id="template_header">
+                                <tr>
+                                    <td id="header_wrapper">
+                                        <h1><?php echo $params['heading'] ?? 'Header'; ?></h1>
+                                    </td>
+                                </tr>
+                            </table>
+                            <!-- End Header -->
+                        </td>
+                    </tr>
+                    <tr>
+                        <td align="center" valign="top">
+                            <!-- Body -->
+                            <table border="0" cellpadding="0" cellspacing="0" width="600" id="template_body">
+                                <tr>
+                                    <td valign="top" id="body_content">
+                                        <!-- Content -->
+                                        <table border="0" cellpadding="20" cellspacing="0" width="100%">
+                                            <tr>
+                                                <td valign="top">
+                                                    <div id="body_content_inner">
diff --git a/templates/html/email-styles.php b/templates/html/email-styles.php
new file mode 100644
index 0000000000000000000000000000000000000000..5a204dc46b4f59fb70e272bd8733879c982db83f
--- /dev/null
+++ b/templates/html/email-styles.php
@@ -0,0 +1,217 @@
+<?php
+
+use WPDesk\Library\WPEmail\Helpers\ColorConversion;
+
+$params = isset( $params ) ? $params : [];
+
+if ( ! defined( 'ABSPATH' ) ) {
+    exit;
+}
+
+// Load colors.
+$bg        = $params['bg'] ?? '#f8f8f8';
+$body      = $params['body'] ?? '#ffffff';
+$base      = $params['primary'] ?? '#5c9a2c';
+$base_text = ColorConversion::light_or_dark( $base, '#171717', '#ffffff' );
+$text      = $params['text'] ?? '#33333';
+
+// Pick a contrasting color for links.
+$link_color = ColorConversion::is_hex_light( $base ) ? $base : $base_text;
+
+if ( ColorConversion::is_hex_light( $body ) ) {
+    $link_color = ColorConversion::is_hex_light( $base ) ? $base_text : $base;
+}
+
+$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.
+?>
+    body {
+    padding: 0;
+    }
+
+    #wrapper {
+    background-color: <?php echo esc_attr( $bg ); ?>;
+    margin: 0;
+    padding: 70px 0;
+    -webkit-text-size-adjust: none !important;
+    width: 100%;
+    }
+
+    #template_container {
+    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1) !important;
+    background-color: <?php echo esc_attr( $body ); ?>;
+    border: 1px solid <?php echo esc_attr( $bg_darker_10 ); ?>;
+    border-radius: 3px !important;
+    }
+
+    #template_header {
+    background-color: <?php echo esc_attr( $base ); ?>;
+    border-radius: 3px 3px 0 0 !important;
+    color: <?php echo esc_attr( $base_text ); ?>;
+    border-bottom: 0;
+    font-weight: bold;
+    line-height: 100%;
+    vertical-align: middle;
+    font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
+    }
+
+    #template_header h1,
+    #template_header h1 a {
+    color: <?php echo esc_attr( $base_text ); ?>;
+    background-color: inherit;
+    }
+
+    #template_header_image img {
+    margin-left: 0;
+    margin-right: 0;
+    }
+
+    #template_footer td {
+    padding: 0;
+    border-radius: 6px;
+    }
+
+    #template_footer #credit {
+    border: 0;
+    color: <?php echo esc_attr( $text_lighter_40 ); ?>;
+    font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
+    font-size: 12px;
+    line-height: 150%;
+    text-align: center;
+    padding: 24px 0;
+    }
+
+    #template_footer #credit p {
+    margin: 0 0 16px;
+    }
+
+    #body_content {
+    background-color: <?php echo esc_attr( $body ); ?>;
+    }
+
+    #body_content table td {
+    padding: 48px 48px 32px;
+    }
+
+    #body_content table td td {
+    padding: 12px;
+    }
+
+    #body_content table td th {
+    padding: 12px;
+    }
+
+    #body_content td ul.wc-item-meta {
+    font-size: small;
+    margin: 1em 0 0;
+    padding: 0;
+    list-style: none;
+    }
+
+    #body_content td ul.wc-item-meta li {
+    margin: 0.5em 0 0;
+    padding: 0;
+    }
+
+    #body_content td ul.wc-item-meta li p {
+    margin: 0;
+    }
+
+    #body_content p {
+    margin: 0 0 16px;
+    }
+
+    #body_content_inner {
+    color: <?php echo esc_attr( $text_lighter_20 ); ?>;
+    font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
+    font-size: 14px;
+    line-height: 150%;
+    text-align: <?php echo is_rtl() ? 'right' : 'left'; ?>;
+    }
+
+    .td {
+    color: <?php echo esc_attr( $text_lighter_20 ); ?>;
+    border: 1px solid <?php echo esc_attr( $body_darker_10 ); ?>;
+    vertical-align: middle;
+    }
+
+    .address {
+    padding: 12px;
+    color: <?php echo esc_attr( $text_lighter_20 ); ?>;
+    border: 1px solid <?php echo esc_attr( $body_darker_10 ); ?>;
+    }
+
+    .text {
+    color: <?php echo esc_attr( $text ); ?>;
+    font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
+    }
+
+    .link {
+    color: <?php echo esc_attr( $link_color ); ?>;
+    }
+
+    #header_wrapper {
+    padding: 36px 48px;
+    display: block;
+    }
+
+    h1 {
+    color: <?php echo esc_attr( $base ); ?>;
+    font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
+    font-size: 30px;
+    font-weight: 300;
+    line-height: 150%;
+    margin: 0;
+    text-align: <?php echo is_rtl() ? 'right' : 'left'; ?>;
+    text-shadow: 0 1px 0 <?php echo esc_attr( $base_lighter_20 ); ?>;
+    }
+
+    h2 {
+    color: <?php echo esc_attr( $base ); ?>;
+    display: block;
+    font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
+    font-size: 18px;
+    font-weight: bold;
+    line-height: 130%;
+    margin: 0 0 18px;
+    text-align: <?php echo is_rtl() ? 'right' : 'left'; ?>;
+    }
+
+    h3 {
+    color: <?php echo esc_attr( $base ); ?>;
+    display: block;
+    font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
+    font-size: 16px;
+    font-weight: bold;
+    line-height: 130%;
+    margin: 16px 0 8px;
+    text-align: <?php echo is_rtl() ? 'right' : 'left'; ?>;
+    }
+
+    a {
+    color: <?php echo esc_attr( $link_color ); ?>;
+    font-weight: normal;
+    text-decoration: underline;
+    }
+
+    img {
+    border: none;
+    display: inline-block;
+    font-size: 14px;
+    font-weight: bold;
+    height: auto;
+    outline: none;
+    text-decoration: none;
+    text-transform: capitalize;
+    vertical-align: middle;
+    margin-<?php echo is_rtl() ? 'left' : 'right'; ?>: 10px;
+    max-width: 100%;
+    }
+<?php
diff --git a/templates/plain/email-content.php b/templates/plain/email-content.php
new file mode 100644
index 0000000000000000000000000000000000000000..f9806149f14c04c3659c766ac675c6acddb3f540
--- /dev/null
+++ b/templates/plain/email-content.php
@@ -0,0 +1,6 @@
+<?php
+
+$params = $params ?? [];
+
+?>
+<?php echo wp_kses_post( $params['content'] ); ?>
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();
+
+
+