diff --git a/.gitignore b/.gitignore
index 8dd78ba1d24d2c0728739f77a50575dab3379bd2..81a4fdc1696316a178d80ecaa4bde72fa9a57fc6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@ ci.config.yaml
 channels.config.yaml
 .pytest_cache
 configs
+demo.sh
diff --git a/ci/gitlab/tests/lint.yaml b/ci/gitlab/tests/lint.yaml
index 130c3a7e2ed4f02f2b378d3e6e3dec266d3ae203..744667a23413f8310e5474e8ce22bbd39cebdbb1 100644
--- a/ci/gitlab/tests/lint.yaml
+++ b/ci/gitlab/tests/lint.yaml
@@ -1,5 +1,6 @@
 test-linting:
   stage: test
   script:
-    - python3 -m flake8 --config flake8.conf ./main.py ./ci
+    - python3 -m flake8 --config flake8.conf ./main.py ./notify
+    - python3 -m mypy --follow-imports=silent --ignore-missing-imports --show-column-numbers --strict ./main.py ./notify
   retry: 2
diff --git a/main.py b/main.py
index 87adbe795165befb9a4658d64e87e8a37829a561..c1188dcb0d5f0b3e87aaef88afaf95349f4f0f62 100644
--- a/main.py
+++ b/main.py
@@ -1,6 +1,7 @@
 import argparse
 import os
 from datetime import date
+from typing import Any
 
 from notify.config import load_config, build_channels
 from notify.timeline.basic import BasicTimelineIterator, FixedDay
@@ -8,7 +9,7 @@ from notify.messages.generator import build_notification
 from notify.calendar.calendar import Calendar
 
 
-def parse_args():
+def parse_args() -> Any:
     parser = argparse.ArgumentParser("Daily notifications")
     parser.add_argument("--config", help="Path to config file",
                         default=[], required=True, action="append")
@@ -17,12 +18,12 @@ def parse_args():
     return parser.parse_args()
 
 
-def is_real_run(args):
+def is_real_run(args: Any) -> bool:
     return args.live_run is True \
         or os.environ.get("DO_REAL_RUN", "false") == "true"
 
 
-def get_date(args) -> date:
+def get_date(args: Any) -> date:
     day_var = os.environ.get("OPT_OVERRIDE_DAY")
     if day_var:
         return date.fromisoformat(day_var)
@@ -32,7 +33,7 @@ def get_date(args) -> date:
         return date.fromisoformat(args.day)
 
 
-def main():
+def main() -> None:
     args = parse_args()
 
     config = load_config(args.config)
diff --git a/notify/__init__.py b/notify/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/notify/calendar/__init__.py b/notify/calendar/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/notify/calendar/__tests__/test_calendar.py b/notify/calendar/__tests__/test_calendar.py
index 20d803c3bf51052305fa986fde0f44b0fde47d3c..fb0d613775db08bc6ac98fd7c1daaef0459e22f6 100644
--- a/notify/calendar/__tests__/test_calendar.py
+++ b/notify/calendar/__tests__/test_calendar.py
@@ -5,7 +5,7 @@ from notify.calendar.calendar import Calendar
 
 
 @fixture
-def calendar():
+def calendar() -> Calendar:
     return Calendar([
         "exclude_all",
         "include_weekdays",
@@ -24,19 +24,19 @@ def calendar():
     ])
 
 
-def test_weekday_detection(calendar: Calendar):
+def test_weekday_detection(calendar: Calendar) -> None:
     assert calendar.match_day(date(2022, 7, 22)) is True
     assert calendar.match_day(date(2022, 7, 23)) is False
     assert calendar.match_day(date(2022, 7, 25)) is True
 
 
-def test_holiday_detection(calendar: Calendar):
+def test_holiday_detection(calendar: Calendar) -> None:
     # 12.26 is a monday but it is Christmas so it should not be a workday
     assert calendar.match_day(date(2022, 12, 26)) is False
     assert calendar.match_day(date(2022, 12, 27)) is True
 
 
-def test_midweek(calendar: Calendar):
+def test_midweek(calendar: Calendar) -> None:
     assert calendar.match_day(date(2022, 9, 13)) is True
     assert calendar.match_day(date(2022, 9, 14)) is False
     assert calendar.match_day(date(2022, 9, 15)) is True
diff --git a/notify/calendar/calendar.py b/notify/calendar/calendar.py
index b352978326d01c06b79414c358d7c7d6a05bd872..9a529d63134ca4902a585ad5f35724bb3177488b 100644
--- a/notify/calendar/calendar.py
+++ b/notify/calendar/calendar.py
@@ -1,11 +1,12 @@
 from datetime import date
+from typing import Any
 
 from .rules.rule import CalendarRule
 from .rules.loader import load_rules
 
 
 class Calendar:
-    def __init__(self, rules_config: list):
+    def __init__(self, rules_config: list[Any]) -> None:
         self._rules: list[CalendarRule] = load_rules(rules_config)
 
     def match_day(self, qdate: date) -> bool:
diff --git a/notify/calendar/rules/__init__.py b/notify/calendar/rules/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/notify/calendar/rules/__tests__/test_exclude_all.py b/notify/calendar/rules/__tests__/test_exclude_all.py
index 367dd6dc130c0a40bee3047c639e4d4df7a17841..518df4a1abe2dd1eedc915247b0521e81d312818 100644
--- a/notify/calendar/rules/__tests__/test_exclude_all.py
+++ b/notify/calendar/rules/__tests__/test_exclude_all.py
@@ -1,7 +1,8 @@
 from datetime import date
-from notify.calendar.rules.exclude_all import ExcludeAll, RuleResult
+from notify.calendar.rules.exclude_all import ExcludeAll
+from notify.calendar.rules.rule import RuleResult
 
 
-def test_current_date():
+def test_current_date() -> None:
     rule = ExcludeAll()
     assert rule.apply(date.today()) == RuleResult(applicable=True, included=False)
diff --git a/notify/calendar/rules/__tests__/test_exclude_dow.py b/notify/calendar/rules/__tests__/test_exclude_dow.py
index fcc05d5811ef3a18b02f20a09295163277ddbae1..7b76da8c50559cce4e73eb632562e3792bdb3de1 100644
--- a/notify/calendar/rules/__tests__/test_exclude_dow.py
+++ b/notify/calendar/rules/__tests__/test_exclude_dow.py
@@ -1,14 +1,15 @@
 from pytest import fixture
 from datetime import date
-from notify.calendar.rules.exclude_dow import ExcludeDayOfWeek, RuleResult
+from notify.calendar.rules.exclude_dow import ExcludeDayOfWeek
+from notify.calendar.rules.rule import RuleResult
 
 
 @fixture
-def rule():
+def rule() -> ExcludeDayOfWeek:
     return ExcludeDayOfWeek(2)
 
 
-def test_days(rule: ExcludeDayOfWeek):
+def test_days(rule: ExcludeDayOfWeek) -> None:
     assert rule.apply(date(2022, 9, 13)).applicable is False
     assert rule.apply(date(2022, 9, 14)) == RuleResult(applicable=True, included=False)
     assert rule.apply(date(2022, 9, 15)).applicable is False
diff --git a/notify/calendar/rules/__tests__/test_exclude_holidays.py b/notify/calendar/rules/__tests__/test_exclude_holidays.py
index be321cc5e8b226358bea31599e87324213138f34..6d4794fdbd2de48d4da0497d7fb814df68daff96 100644
--- a/notify/calendar/rules/__tests__/test_exclude_holidays.py
+++ b/notify/calendar/rules/__tests__/test_exclude_holidays.py
@@ -1,14 +1,15 @@
 from pytest import fixture
 from datetime import date
-from notify.calendar.rules.exclude_holidays import ExcludeHolidays, RuleResult
+from notify.calendar.rules.exclude_holidays import ExcludeHolidays
+from notify.calendar.rules.rule import RuleResult
 
 
 @fixture
-def rule():
+def rule() -> ExcludeHolidays:
     return ExcludeHolidays("HU")
 
 
-def test_christmas(rule: ExcludeHolidays):
+def test_christmas(rule: ExcludeHolidays) -> None:
     assert rule.apply(date(2021, 12, 23)).applicable is False
     assert rule.apply(date(2021, 12, 24)) == RuleResult(applicable=True, included=False)
     assert rule.apply(date(2021, 12, 25)) == RuleResult(applicable=True, included=False)
diff --git a/notify/calendar/rules/__tests__/test_include_days.py b/notify/calendar/rules/__tests__/test_include_days.py
index 56e049642506e5f25bb8a3afd665448d2b63d197..84a017709f13557aa81350f010efb2ab006bcc28 100644
--- a/notify/calendar/rules/__tests__/test_include_days.py
+++ b/notify/calendar/rules/__tests__/test_include_days.py
@@ -1,13 +1,14 @@
 from datetime import date
-from notify.calendar.rules.include_days import IncludeDays, RuleResult
+from notify.calendar.rules.include_days import IncludeDays
+from notify.calendar.rules.rule import RuleResult
 
 
-def test_no_included_days():
+def test_no_included_days() -> None:
     rule = IncludeDays(days=[])
     assert rule.apply(date(2022, 9, 18)).applicable is False
 
 
-def test_one_included_day():
+def test_one_included_day() -> None:
     rule = IncludeDays(days=[date(2022, 9, 18)])
 
     assert rule.apply(date(2022, 9, 17)).applicable is False
@@ -15,7 +16,7 @@ def test_one_included_day():
     assert rule.apply(date(2022, 9, 19)).applicable is False
 
 
-def test_two_included_day():
+def test_two_included_day() -> None:
     rule = IncludeDays(days=[date(2022, 9, 19), date(2022, 9, 18)])
 
     assert rule.apply(date(2022, 9, 17)).applicable is False
diff --git a/notify/calendar/rules/__tests__/test_include_weekdays.py b/notify/calendar/rules/__tests__/test_include_weekdays.py
index 70dad37c9d2207d5f6014d52d9242c2858ae24fc..03ee9367fd6438158b6291806213d5f9207e7bc7 100644
--- a/notify/calendar/rules/__tests__/test_include_weekdays.py
+++ b/notify/calendar/rules/__tests__/test_include_weekdays.py
@@ -1,14 +1,15 @@
 from pytest import fixture
 from datetime import date
-from notify.calendar.rules.include_weekdays import IncludeWeekdays, RuleResult
+from notify.calendar.rules.include_weekdays import IncludeWeekdays
+from notify.calendar.rules.rule import RuleResult
 
 
 @fixture
-def rule():
+def rule() -> IncludeWeekdays:
     return IncludeWeekdays()
 
 
-def test_weekdays(rule: IncludeWeekdays):
+def test_weekdays(rule: IncludeWeekdays) -> None:
     assert rule.apply(date(2022, 9, 19)) == RuleResult(applicable=True, included=True)
     assert rule.apply(date(2022, 9, 20)) == RuleResult(applicable=True, included=True)
     assert rule.apply(date(2022, 9, 21)) == RuleResult(applicable=True, included=True)
@@ -16,6 +17,6 @@ def test_weekdays(rule: IncludeWeekdays):
     assert rule.apply(date(2022, 9, 23)) == RuleResult(applicable=True, included=True)
 
 
-def test_weekend(rule: IncludeWeekdays):
+def test_weekend(rule: IncludeWeekdays) -> None:
     assert rule.apply(date(2022, 9, 24)).applicable is False
     assert rule.apply(date(2022, 9, 25)).applicable is False
diff --git a/notify/calendar/rules/exclude_holidays.py b/notify/calendar/rules/exclude_holidays.py
index fbc24e78a8e2dfbdf3c48edeba8f784f3072334c..dfa4229d96262e63e62ef96c15cd66d47b80418a 100644
--- a/notify/calendar/rules/exclude_holidays.py
+++ b/notify/calendar/rules/exclude_holidays.py
@@ -4,9 +4,9 @@ from .rule import CalendarRule, RuleResult
 
 
 class ExcludeHolidays(CalendarRule):
-    def __init__(self, country: str):
+    def __init__(self, country: str) -> None:
         super().__init__()
-        self._holidays = pyholidays.country_holidays(country)
+        self._holidays = pyholidays.country_holidays(country)  # type: ignore
 
     def apply(self, day: date) -> RuleResult:
         if day in self._holidays:
diff --git a/notify/calendar/rules/loader.py b/notify/calendar/rules/loader.py
index 7014caeeae5573274ea378717f52ae4d635cab17..394c383a8082c443adeb5f468089c04014075ecb 100644
--- a/notify/calendar/rules/loader.py
+++ b/notify/calendar/rules/loader.py
@@ -1,7 +1,8 @@
+from typing import Any
 from .rule import CalendarRule
 
 
-def load_rules(rule_config_list: list) -> list[CalendarRule]:
+def load_rules(rule_config_list: list[Any]) -> list[CalendarRule]:
     rules: list[CalendarRule] = []
 
     for rule_config in rule_config_list:
@@ -14,7 +15,7 @@ def load_rules(rule_config_list: list) -> list[CalendarRule]:
     return rules
 
 
-def load_rule(rule_config: dict) -> CalendarRule:
+def load_rule(rule_config: dict[str, Any]) -> CalendarRule:
     options = rule_config["options"] if "options" in rule_config else {}
 
     if rule_config["name"] == "exclude_all":
diff --git a/notify/calendar/rules/rule.py b/notify/calendar/rules/rule.py
index a27ff93b0dd38fce41dc4265340745338040f00d..dc27bd2757910c5b744f4d86d96f9d9bbf9f380c 100644
--- a/notify/calendar/rules/rule.py
+++ b/notify/calendar/rules/rule.py
@@ -9,7 +9,7 @@ class RuleResult():
 
 
 class CalendarRule():
-    def __init__(self):
+    def __init__(self) -> None:
         pass
 
     def apply(self, day: date) -> RuleResult:
diff --git a/notify/channels/__init__.py b/notify/channels/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/notify/channels/channel.py b/notify/channels/channel.py
index 2ef65e42dd96ebd5fd3c3744e571d980ae96ebbc..8ac0c6a9cec5693aca7da57419f6efcd34437d36 100644
--- a/notify/channels/channel.py
+++ b/notify/channels/channel.py
@@ -2,8 +2,8 @@ from ..messages.notification import Notification
 
 
 class NotificationChannel:
-    def __init__(self):
+    def __init__(self) -> None:
         pass
 
-    def send_notification(message: Notification):
+    def send_notification(self, message: Notification) -> None:
         pass
diff --git a/notify/channels/email.py b/notify/channels/email.py
index 4ab6df13b1d7122fcb1b28dd50cf5fee8306b76f..e88d076d72897643264096c28dc03fea44d14b4d 100644
--- a/notify/channels/email.py
+++ b/notify/channels/email.py
@@ -2,7 +2,7 @@ from typing import Optional
 from .channel import NotificationChannel
 from ..messages.notification import Notification
 
-from redmail import EmailSender
+from redmail.email.sender import EmailSender
 
 
 class EmailChannel(NotificationChannel):
@@ -10,7 +10,7 @@ class EmailChannel(NotificationChannel):
         self, smtp_username: str, smtp_password: str, smtp_server: str,
         smtp_port: int, from_email: str, to_emails: list[str],
         local_hostname: Optional[str] = None
-    ):
+    ) -> None:
         self._from_email = from_email
         self._to_emails = to_emails
 
@@ -22,9 +22,9 @@ class EmailChannel(NotificationChannel):
             local_hostname=local_hostname
         )
 
-    def send_notification(self, message: Notification):
+    def send_notification(self, message: Notification) -> None:
         try:
-            self._client.connect()
+            self._client.connect()  # type: ignore
             for to_email in self._to_emails:
                 print("Sending emails to", to_email)
                 try:
@@ -36,6 +36,6 @@ class EmailChannel(NotificationChannel):
                     )
                 except Exception as e:
                     print(f"Failed to send email: {e}")
-            self._client.close()
+            self._client.close()  # type: ignore
         except Exception as e:
             print(f"Failed to send email: {e}")
diff --git a/notify/channels/matrix.py b/notify/channels/matrix.py
index 289f06080d84cbac7b2f5a5694c94159dcb6bb55..97ac7b6721665ea572f0e0407b9fb51b1e78c7e8 100644
--- a/notify/channels/matrix.py
+++ b/notify/channels/matrix.py
@@ -6,14 +6,14 @@ from ..messages.notification import Notification
 
 
 class MatrixMessageChannel(NotificationChannel):
-    def __init__(self, bot_server: str, instance_id: str, secret: str, room_ids: list[str]):
+    def __init__(self, bot_server: str, instance_id: str, secret: str, room_ids: list[str]) -> None:
         super().__init__()
         self._bot_server = bot_server
         self._instance_id = instance_id
         self._secret = secret
         self.room_ids = room_ids
 
-    def send_notification(self, message: Notification):
+    def send_notification(self, message: Notification) -> None:
         for room_id in self.room_ids:
             print("Sending message to room", room_id)
 
diff --git a/notify/channels/vonage_sms.py b/notify/channels/vonage_sms.py
index b970e3a3cb4bdbf0d3f64174d821a5f95ccf7736..80b8fd64a282f69c9ef62340781484a90f2e4914 100644
--- a/notify/channels/vonage_sms.py
+++ b/notify/channels/vonage_sms.py
@@ -5,13 +5,13 @@ from ..messages.notification import Notification
 
 
 class VonageSmsChannel(NotificationChannel):
-    def __init__(self, key: str, secret: str, sender: str, to_numbers: list[str]):
+    def __init__(self, key: str, secret: str, sender: str, to_numbers: list[str]) -> None:
         super().__init__()
         self._client = nexmo.Client(key=key, secret=secret)
         self._numbers = to_numbers
         self._sender = sender
 
-    def send_notification(self, message: Notification):
+    def send_notification(self, message: Notification) -> None:
         for number in self._numbers:
             print("Sending SMS to", number)
             try:
diff --git a/notify/config.py b/notify/config.py
index 2283ec9acf6012fcf89a4f770b3cb1abf318203e..3470f661dea77a7906b420eee4664eb96f3787aa 100644
--- a/notify/config.py
+++ b/notify/config.py
@@ -1,4 +1,4 @@
-from typing import Union
+from typing import Any, Generator, Union
 import yaml
 
 from deepmerge import always_merger
@@ -15,8 +15,8 @@ CHANNEL_TYPES = {
 }
 
 
-def load_config(files: Union[str, list[str]]):
-    config = {}
+def load_config(files: Union[str, list[str]]) -> Any:
+    config: Any = {}
 
     if isinstance(files, str):
         files = [files]
@@ -29,7 +29,7 @@ def load_config(files: Union[str, list[str]]):
     return config
 
 
-def build_channels(config) -> list[NotificationChannel]:
+def build_channels(config: Any) -> Generator[NotificationChannel, None, None]:
     for channel in config["channels"]:
         type = channel["type"]
         if type not in CHANNEL_TYPES:
diff --git a/notify/messages/__init__.py b/notify/messages/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/notify/messages/__tests__/test_generator.py b/notify/messages/__tests__/test_generator.py
index 5dc23dd10ec4f815e599834e067a8b774e35f423..3c578efea9ea9f1e340eeee3714e3282d1f2a0e3 100644
--- a/notify/messages/__tests__/test_generator.py
+++ b/notify/messages/__tests__/test_generator.py
@@ -1,3 +1,4 @@
+from typing import Any
 from pytest import fixture
 from datetime import date
 
@@ -8,7 +9,7 @@ from notify.messages.generator import build_notification
 
 
 @fixture
-def basic_timeline_iterator():
+def basic_timeline_iterator() -> BasicTimelineIterator:
     return BasicTimelineIterator(
         workday_calendar=Calendar([
             "exclude_all",
@@ -31,7 +32,7 @@ def basic_timeline_iterator():
 
 
 @fixture
-def template_config():
+def template_config() -> Any:
     return {
         "message": {
             "title": "Daily standup",
@@ -41,13 +42,14 @@ def template_config():
     }
 
 
-def test_weekend(basic_timeline_iterator: TimelineIterator, template_config):
+def test_weekend(basic_timeline_iterator: TimelineIterator, template_config: Any) -> None:
     msg = build_notification(basic_timeline_iterator, template_config, date(2022, 9, 25))
     assert msg is None
 
 
-def test_message_generation(basic_timeline_iterator: TimelineIterator, template_config):
+def test_message_generation(basic_timeline_iterator: TimelineIterator, template_config: Any) -> None:
     msg = build_notification(basic_timeline_iterator, template_config, date(2022, 9, 21))
+    assert msg is not None
     assert msg.title == "Daily standup"
     assert msg.message == """Dear Team Tirith!
 
diff --git a/notify/messages/generator.py b/notify/messages/generator.py
index eae6588c4cf809a2fab5b3eded4722bd1b3752d3..48100487ff3547ea9590117c065e3874101a5f5a 100644
--- a/notify/messages/generator.py
+++ b/notify/messages/generator.py
@@ -1,3 +1,4 @@
+from typing import Any, Optional
 import jinja2
 from datetime import date
 
@@ -5,21 +6,21 @@ from ..timeline.iterator import TimelineIterator, CalendarDay
 from .notification import Notification
 
 
-def render(tempalte_file, data) -> str:
+def render(tempalte_file: str, data: Any) -> str:
     templateLoader = jinja2.FileSystemLoader(searchpath="./templates")
     templateEnv = jinja2.Environment(loader=templateLoader)
     template = templateEnv.get_template(tempalte_file)
     return template.render(data)
 
 
-def day_to_data(day: CalendarDay) -> dict:
+def day_to_data(day: CalendarDay) -> dict[str, str]:
     return {
         **day.__dict__,
         "dow": day.day.strftime('%A')
     }
 
 
-def build_notification(iter: TimelineIterator, config, starting_day: date) -> Notification:
+def build_notification(iter: TimelineIterator, config: Any, starting_day: date) -> Optional[Notification]:
     iter.set_day(starting_day)
 
     days: list[CalendarDay] = []
diff --git a/notify/timeline/__init__.py b/notify/timeline/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/notify/timeline/__tests__/test_basic.py b/notify/timeline/__tests__/test_basic.py
index 6299dc6aafc54f11d87d348b254fdefbad6b79af..fabe132134ef17c1fb4095c0aa93ddc4e4d4ea87 100644
--- a/notify/timeline/__tests__/test_basic.py
+++ b/notify/timeline/__tests__/test_basic.py
@@ -1,12 +1,13 @@
 from pytest import fixture
 from datetime import date
 
-from notify.timeline.basic import BasicTimelineIterator, FixedDay, CalendarDay
+from notify.timeline.basic import BasicTimelineIterator, FixedDay
+from notify.timeline.iterator import CalendarDay
 from notify.calendar.calendar import Calendar
 
 
 @fixture
-def basic_timeline():
+def basic_timeline() -> BasicTimelineIterator:
     return BasicTimelineIterator(
         workday_calendar=Calendar([
             "exclude_all",
@@ -28,12 +29,12 @@ def basic_timeline():
     )
 
 
-def test_fixed_day(basic_timeline: BasicTimelineIterator):
+def test_fixed_day(basic_timeline: BasicTimelineIterator) -> None:
     basic_timeline.set_day(date(2022, 9, 21))
     assert basic_timeline.__next__() == CalendarDay(day=date(2022, 9, 21), moderator="a")
 
 
-def test_iteration(basic_timeline: BasicTimelineIterator):
+def test_iteration(basic_timeline: BasicTimelineIterator) -> None:
     expected_items = [
         CalendarDay(day=date(2022, 9, 21), moderator="a"),
         CalendarDay(day=date(2022, 9, 22), moderator="a"),
@@ -54,7 +55,7 @@ def test_iteration(basic_timeline: BasicTimelineIterator):
             break
 
 
-def test_far_in_future(basic_timeline: BasicTimelineIterator):
+def test_far_in_future(basic_timeline: BasicTimelineIterator) -> None:
     expected_items = [
         CalendarDay(day=date(2046, 9, 21), moderator="c"),
         CalendarDay(day=date(2046, 9, 24), moderator="c"),
diff --git a/notify/timeline/basic.py b/notify/timeline/basic.py
index 164b5c650334aa59d3d1c908fc29e8539076186f..f1f4e71f0fc3f4c2c33da8b1604ea737264a2af9 100644
--- a/notify/timeline/basic.py
+++ b/notify/timeline/basic.py
@@ -23,7 +23,7 @@ class BasicTimelineIterator(TimelineIterator):
 
         self._offset_days = self._get_initial_offset()
 
-    def _get_initial_offset(self):
+    def _get_initial_offset(self) -> int:
         return \
             self._moderators.index(self._fixed_day.moderator) * self._moderator_days + \
             self._moderator_days - self._fixed_day.days_left - 1
diff --git a/requirements.txt b/requirements.txt
index eeed271b15cddb5a6ea8a6f61e22f5cd3dddef7b..dbf7d62daf07714036efa31c3fd66c91ba54e649 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,7 +6,13 @@ redmail
 holidays
 deepmerge
 jinja2
+markdown
 
 # test
 pytest
 flake8
+mypy
+
+# types
+types-requests
+types-PyYAML