diff --git a/district/models.py b/district/models.py
index 21c9d7fd68423de12a6e2dc949e41ed98420b412..fc0bd5d1f73730d53f49463bc555b2ebbb3b9c93 100644
--- a/district/models.py
+++ b/district/models.py
@@ -52,6 +52,7 @@ from shared.models import (
     ExtendedMetadataPageMixin,
     FooterMixin,
     MenuMixin,
+    NewsletterFormMixin,
     SubpageMixin,
 )
 from shared.utils import make_promote_panels, strip_all_html_tags, trim_to_length
@@ -73,6 +74,7 @@ class DistrictHomePage(
     MetadataPageMixin,
     CalendarMixin,
     FooterMixin,
+    NewsletterFormMixin,
     Page,
 ):
     ### FIELDS
@@ -254,6 +256,7 @@ class DistrictHomePage(
             ],
             gettext_lazy("Kontakty"),
         ),
+        *NewsletterFormMixin.settings_panels,
         MultiFieldPanel(
             [
                 FieldPanel("footer_person_list"),
diff --git a/shared/blocks.py b/shared/blocks.py
index 0e5b066608cdcab065fdce02cb63917a0fab408d..d4d366443637f9661095177da7f0704f4ceaa812 100644
--- a/shared/blocks.py
+++ b/shared/blocks.py
@@ -1074,9 +1074,6 @@ class FooterLinksBlock(blocks.StructBlock):
 
 
 class NewsletterSubscriptionBlock(blocks.StructBlock):
-    subscription_id = blocks.CharBlock(label="ID newsletteru")
-    access_token = blocks.CharBlock(label="Access token")
-
     design = blocks.StructBlock(
         local_blocks=[
             ("icon", ImageChooserBlock(label="Vyberte si ikonku k formuláři")),
@@ -1142,11 +1139,6 @@ class NewsletterSubscriptionBlock(blocks.StructBlock):
     config = blocks.StructBlock(
         local_blocks=[
             (
-                "require_confirmation",
-                blocks.BooleanBlock(
-                    label="Požadovat zaslání ověřovacího e-mailu?", required=False
-                ),
-            )(
                 "show_name_input",
                 blocks.BooleanBlock(
                     label="Umožnit uživateli přidat jméno a příjmení?", required=False
@@ -1168,7 +1160,6 @@ class NewsletterSubscriptionBlock(blocks.StructBlock):
             ),
         ],
         default=[
-            ("require_confirmation", True),
             ("show_name_input", False),
             ("force_subscribe", True),
             ("send_timezone", False),
diff --git a/shared/models.py b/shared/models.py
index f9e8b0bbbe313d4a6aec45497170a091a85541b2..0dc2ab9eb46fe2a7948416b8d159c93d9a911ad0 100644
--- a/shared/models.py
+++ b/shared/models.py
@@ -1,13 +1,12 @@
-import json
 import logging
-from datetime import date, timedelta
 
-import requests
-from django.core.cache import cache
+from django.core.serializers.json import DjangoJSONEncoder
 from django.db import models
+from django.http import JsonResponse
 from django.utils import timezone
-from icalevents import icalevents
+from requests import request
 from wagtail.admin.panels import FieldPanel, MultiFieldPanel, PublishingPanel
+from wagtail.contrib.routable_page.models import RoutablePageMixin, route
 from wagtail.fields import StreamField
 from wagtail.models import Page
 
@@ -21,6 +20,58 @@ from shared.blocks import (
 logger = logging.getLogger(__name__)
 
 
+class NewsletterFormMixin(RoutablePageMixin, models.Model):
+    subscription_id = models.CharField(label="ID newsletteru")
+    access_token = models.CharField(label="Access token")
+    require_confirmation = models.BooleanField(
+        label="Požadovat zaslání ověřovacího e-mailu?", default=True
+    )
+
+    settings_panels = [
+        MultiFieldPanel(
+            [
+                FieldPanel("subscription_id"),
+                FieldPanel("access_token"),
+            ],
+            heading="Nastavení API newsletteru",
+        ),
+    ]
+
+    @route(r"^newsletter/$", name="newsletter")
+    def newsletter_post(self, posted):
+        if posted.method == "POST":
+            mailtrain_request = {"EMAIL": posted.POST["email"]}
+            if "first_name" in posted.POST and "last_name" in posted.POST:
+                mailtrain_request.update(
+                    {
+                        "MERGE_FIRST_NAME": posted.POST["first_name"],
+                        "MERGE_LAST_NAME": posted.POST["last_name"],
+                    }
+                )
+            if "force_subscribe" in posted.GET:
+                mailtrain_request.update(
+                    {
+                        "FORCE_SUBSCRIBE": "yes",
+                    }
+                )
+            if "timezone" in posted.POST:
+                mailtrain_request.update({"TIMEZONE": posted.POST["timezone"]})
+            if self.require_confirmation:
+                mailtrain_request.update({"REQUIRE_CONFIRMATION": "yes"})
+            return JsonResponse(
+                request(
+                    "POST",
+                    f"https://mailtrain.pirati.cz/api/subscribe/{self.subscription_id}?access_token={self.access_token}",
+                    mailtrain_request,
+                ).json(),
+                encoder=DjangoJSONEncoder,
+            )
+        raise ValueError("Request has to be post!")
+
+    class Meta:
+        abstract = True
+
+
 class SubpageMixin:
     """Must be used in class definition before MetadataPageMixin!"""
 
diff --git a/shared/static/shared/js/vue-formulate-helper.js b/shared/static/shared/js/vue-formulate-helper.js
index edc7cfdde91bad424a7a84dd7710933ba8b43b9a..e7fc14fd45be20112447aa85e4dd59991567a43a 100644
--- a/shared/static/shared/js/vue-formulate-helper.js
+++ b/shared/static/shared/js/vue-formulate-helper.js
@@ -2,3 +2,18 @@ Vue.use(VueFormulate, {
   plugins: [VueFormulateI18n.cs],
   locale: "cs",
 });
+
+Vue.use(Vue.component("MailtrainFormContainer", {
+    props: {
+        url: String,
+    },
+    methods: {
+        onSubmit(...data) {
+            // Intl.DateTimeFormat().resolvedOptions().timeZone)
+            console.log(this, ...data);
+        },
+    },
+    render(createElement) {
+        return createElement("div", {}, this.$slots.default);
+    }
+}))
diff --git a/shared/templates/shared/blocks/newsletter_subscription_block.html b/shared/templates/shared/blocks/newsletter_subscription_block.html
index 043f39103c52bb8b6c80be6bba9dc7ae23321405..41793f6ba3832794f146231e505b39a99c2c637b 100644
--- a/shared/templates/shared/blocks/newsletter_subscription_block.html
+++ b/shared/templates/shared/blocks/newsletter_subscription_block.html
@@ -24,31 +24,40 @@
                     {{ self.design.subtitle }}
                 </span>
                 <div class="flex flex-col items-start">
-                    <FormulateForm method="POST" action="{% fullpageurl page.root_page %}/newsletter" #default="{ isLoading, hasErrors }">
-                        {% csrf_token %}
-                        {% if self.config.show_name_input %}
-                            <FormulateInput type="text" name="first_name" :element-class="() => ['text-input', 'bg-white', 'form-field__control', 'mb-3', 'w-full']" label="{{ self.design.labels.first_name }}"
-                                placeholder="{{ self.design.labels.first_name }}" validation="required" error-behavior="value"
+                    <MailtrainFormContainer url="{% if self.config.force_subscribe %}{% routablepageurl page.root_page 'newsletter' force_subscribe=True %}{% else %}{% routablepageurl page.root_page 'newsletter' %}{% endif %}">
+                        <FormulateForm @submit="onSubmit" #default="{ isLoading, hasErrors }">
+                            {% csrf_token %}
+                            {% if self.config.send_timezone %}
+                                <FormulateInput
+                                    type="hidden"
+                                    name="send_timezone"
+                                    value="True"
+                                />
+                            {% endif %}
+                            {% if self.config.show_name_input %}
+                                <FormulateInput type="text" name="first_name" :element-class="() => ['text-input', 'bg-white', 'form-field__control', 'mb-3', 'w-full']" label="{{ self.design.labels.first_name }}"
+                                    placeholder="{{ self.design.labels.first_name }}" validation="required" error-behavior="value"
+                                    label-class="sr-only" />
+                                <FormulateInput type="text" name="last_name" :element-class="() => ['text-input', 'bg-white', 'form-field__control', 'mb-3', 'w-full']" label="{{ self.design.labels.last_name }}"
+                                    placeholder="{{ self.design.labels.last_name }}" validation="required" error-behavior="value"
+                                    label-class="sr-only" />
+                            {% endif %}
+                            <FormulateInput type="email" name="email" :element-class="() => ['text-input', 'bg-white', 'form-field__control', 'mb-3', 'w-full']" label="{{ self.design.labels.email }}"
+                                placeholder="{{ self.design.labels.email }}" validation="required|email" error-behavior="value"
                                 label-class="sr-only" />
-                            <FormulateInput type="text" name="last_name" :element-class="() => ['text-input', 'bg-white', 'form-field__control', 'mb-3', 'w-full']" label="{{ self.design.labels.last_name }}"
-                                placeholder="{{ self.design.labels.last_name }}" validation="required" error-behavior="value"
-                                label-class="sr-only" />
-                        {% endif %}
-                        <FormulateInput type="email" name="email" :element-class="() => ['text-input', 'bg-white', 'form-field__control', 'mb-3', 'w-full']" label="{{ self.design.labels.email }}"
-                            placeholder="{{ self.design.labels.email }}" validation="required|email" error-behavior="value"
-                            label-class="sr-only" />
-                        <div class="checkbox form-field__control flex items-center mb-3">
-                            <FormulateInput type="checkbox" label="{% include_block self.design.consent %}" label-class="text-xs font-alt font-light" validation="required" error-behavior="value" />
-                        </div>
-                        <FormulateErrors />
-                        <button type="submit" :disabled="isLoading || hasErrors" class="btn btn--black btn--to-yellow-500 btn--hoveractive uppercase">
-                            <span class="btn__body-wrap">
-                                <span v-html="isLoading ? 'Odesílám...' : '{{ self.design.button }}'" class="btn__body text-lg lg:text-base">
-                                    Odebírat
+                            <div class="checkbox form-field__control flex items-center mb-3">
+                                <FormulateInput type="checkbox" label="{% include_block self.design.consent %}" label-class="text-xs font-alt font-light" validation="required" error-behavior="value" />
+                            </div>
+                            <FormulateErrors />
+                            <button type="submit" :disabled="isLoading || hasErrors" class="btn btn--black btn--to-yellow-500 btn--hoveractive uppercase">
+                                <span class="btn__body-wrap">
+                                    <span v-html="isLoading ? 'Odesílám...' : '{{ self.design.button }}'" class="btn__body text-lg lg:text-base">
+                                        Odebírat
+                                    </span>
                                 </span>
-                            </span>
-                        </button>
-                    </FormulateForm>
+                            </button>
+                        </FormulateForm>
+                    </MailtrainFormContainer>
                 </div>
             </div>
         </div>
diff --git a/uniweb/models.py b/uniweb/models.py
index 423ad0481b51c2436c7197d100ae02d1333cfd08..d0093886ac7a46d811b777401092273f0125e4cc 100644
--- a/uniweb/models.py
+++ b/uniweb/models.py
@@ -32,6 +32,7 @@ from shared.models import (
     ExtendedMetadataHomePageMixin,
     ExtendedMetadataPageMixin,
     FooterMixin,
+    NewsletterFormMixin,
     SubpageMixin,
 )
 from shared.utils import make_promote_panels, strip_all_html_tags, trim_to_length
@@ -301,7 +302,12 @@ class UniwebArticleTag(TaggedItemBase):
 
 
 class UniwebHomePage(
-    Page, ExtendedMetadataHomePageMixin, MetadataPageMixin, CalendarMixin, FooterMixin
+    Page,
+    ExtendedMetadataHomePageMixin,
+    MetadataPageMixin,
+    CalendarMixin,
+    NewsletterFormMixin,
+    FooterMixin,
 ):
     ### FIELDS
 
@@ -364,6 +370,7 @@ class UniwebHomePage(
             ],
             "nastavení webu",
         ),
+        *NewsletterFormMixin.settings_panels,
         FieldPanel("calendar_url"),
         MultiFieldPanel(
             [