diff --git a/dovecot/.dockerignore b/dovecot/.dockerignore
new file mode 100644
index 0000000000000000000000000000000000000000..68eb57dbfc589324ae08b8ba30d0eee0dab636c8
--- /dev/null
+++ b/dovecot/.dockerignore
@@ -0,0 +1,4 @@
+*
+!*.sieve
+!entrypoint
+!patch.diff
diff --git a/dovecot/Dockerfile b/dovecot/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..746b646f01555c65c8ec220338be1df2e6448c69
--- /dev/null
+++ b/dovecot/Dockerfile
@@ -0,0 +1,35 @@
+FROM buildpack-deps:buster as delete_to_trash
+RUN apt-get update && \
+    DEBIAN_FRONTEND=noninteractive  apt-get install -y dovecot-dev && \
+    git clone https://github.com/pali/dovecot_deleted_to_trash && \
+    cd dovecot_deleted_to_trash && \
+    make
+
+FROM debian:buster-slim
+RUN apt-get update && \
+    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
+        dovecot-ldap \
+        dovecot-lmtpd \
+        dovecot-imapd \
+        dovecot-sieve \
+        patch \
+        ssl-cert \
+        time \
+    && \
+    rm -rf /tmp/* /var/tmp/* /var/lib/apt/lists/* /var/cache/apt/archives/*
+COPY --from=delete_to_trash /dovecot_deleted_to_trash/lib_deleted_to_trash_plugin.so /usr/lib/dovecot/modules/
+COPY --from=delete_to_trash /dovecot_deleted_to_trash/95-deleted_to_trash_plugin.conf /etc/dovecot/conf.d/
+COPY --chown=root:root entrypoint /entrypoint
+COPY patch.diff /root/
+RUN patch --strip 0 --verbose --directory /etc/dovecot --input /root/patch.diff && \
+    doveconf
+COPY --chown=mail:mail *.sieve /var/lib/dovecot/sieve.d/
+RUN cd /var/lib/dovecot/sieve.d/ && \
+    ls *.sieve | xargs -tn1 sievec && \
+    rm *.svbin
+VOLUME /var/mail
+VOLUME /run/dovecot
+EXPOSE 993 25
+ENTRYPOINT [ "/entrypoint" ]
+CMD [ "dovecot", "-F" ]
+HEALTHCHECK CMD doveadm service status || exit 1
diff --git a/dovecot/README.md b/dovecot/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..adb13d067ddb7d519df3500024cb9d85437bbec8
--- /dev/null
+++ b/dovecot/README.md
@@ -0,0 +1,30 @@
+# Dovecot
+
+> Dovecot container image.
+
+## Exposed interfaces
+
+The containers exposes TCP ports 25 (LMTP) and 993 (IMAPS) and the `lmtp` Unix
+socket in the `/run/dovecot` volume (for LTMP submission).
+
+## Environment variables
+
+Name | Description
+--- | ---
+`LDAP_URIS` | LDAP URI (eg, `ldapi:///`).
+`LDAP_BASEDN` | LDAP base DN (eg, `dc=example,dc=com`).
+
+## Persistence
+
+The mbox files are stored at `/var/mail`.
+
+## License
+
+This software is licensed under the MIT license (see `LICENSE.txt`).
+
+## Author Information
+
+Nimrod Adar, [contact me](mailto:nimrod@shore.co.il) or visit my [website](
+https://www.shore.co.il/). Patches are welcome via [`git send-email`](
+http://git-scm.com/book/en/v2/Git-Commands-Email). The repository is located
+at: <https://www.shore.co.il/git/>.
diff --git a/dovecot/before.sieve b/dovecot/before.sieve
new file mode 100644
index 0000000000000000000000000000000000000000..ee9cb0cee36a765cb920f3517a3009c4ebd8ea44
--- /dev/null
+++ b/dovecot/before.sieve
@@ -0,0 +1,6 @@
+require ["fileinto", "envelope"];
+if anyof (header :contains "X-Spam-Status" "Yes",
+          header :contains "X-Virus-Status" "infected")
+{
+    fileinto "Junk";
+}
diff --git a/dovecot/entrypoint b/dovecot/entrypoint
new file mode 100755
index 0000000000000000000000000000000000000000..b3905bf5be7ff5d32513777cefe62ec342e5ca07
--- /dev/null
+++ b/dovecot/entrypoint
@@ -0,0 +1,16 @@
+#!/bin/sh
+set -eux
+
+install -d -m 755 -o dovecot -g root /var/run/dovecot
+install -d -m 775 -o root -g dovecot /var/mail
+install -d -m 775 -o root -g dovecot /run/dovecot
+time openssl dhparam -out /usr/share/dovecot/dh.pem 4096
+DEBIAN_FRONTEND=noninteractive time make-ssl-cert generate-default-snakeoil --force-overwrite
+
+# I don't know why environment variables aren't expanded and I'm too interested
+# to find out.
+
+sed -i "s@%{env:LDAP_URIS}@$LDAP_URIS@g" /etc/dovecot/dovecot-ldap.conf.ext
+sed -i "s@%{env:LDAP_BASEDN}@$LDAP_BASEDN@g" /etc/dovecot/dovecot-ldap.conf.ext
+
+eval exec "$@"
diff --git a/dovecot/nimrod.sieve b/dovecot/nimrod.sieve
new file mode 100644
index 0000000000000000000000000000000000000000..44a693c15e04110b06b353a19dd73c02c7d7c67e
--- /dev/null
+++ b/dovecot/nimrod.sieve
@@ -0,0 +1,85 @@
+require ["fileinto", "envelope", "imap4flags"];
+if address :is "from" "nimrod@shore.co.il" { setflag "\\seen"; }
+
+if address :is :domain "from" [ "drushim.co.il", "indeed.com", "picaro.co.il", "jobnet.co.il", "cps.co.il", "seev.co.il", "yad2jobs.co.il", "mindu.co.il", "korentec.co.il", "ethosia.com", "ethosia.co.il", "nisha.co.il", "alljob.co.il", "alljobs.co.il", "propel.co.il", "simplyfind.co.il", "jobby.co.il", "niloosoft.com", "qhr.co.il", "dialog.co.il", "taldor.co.il", "linkedin.com", "*.linkedin.com", "hire.withgoogle.com" , "hunterhrms.com", "triplebyte.com", "gun.io", "lever.co", "*.lever.co", "logica-it.co.il" ]
+{
+	fileinto "Wanted";
+}
+elsif anyof (
+    address :is :domain "from" [ "puppetlabs.com", "drivehq.com", "bsdmag.org", "macecraft.com", "rol.co.il", "pointmail.co.za", "agora.co.il", "bsdmag.com", "check.me", "dvorak.org", "perlmaven.com", "itnewsletter.co.il", "aerofs.com", "lastpass.com", "openstack-israel.org", "sdjournal.org", "htisrael.co.il", "github.com", "marriott-email.com", "meetup.com", "8662244.co.il", "software.com.pl", "heroku.com", "eg-innovations.net", "email-marriott.com", "info.docker.com", "docker.com", "docker.io", "onedrive.microsoft.com", "aerofs.com", "m.aerofs.com", "airbnb.com", "circleci.com", "bugs.debian.org", "getcloudify.com", "mqg.org.il", "samerica.co.il", "gigaspaces.com", "getcloudify.org", "email.aol.com", "maccabi-news.co.il", "microfocus.com", "*.microfocus.com", "statscraft.org.il", "novell.com" ],
+    address :is "from" [ "ecomeshek@gmail.com", "ironethaifa@haifa.muni.il" ],
+    address :is :domain "to" [ "openbsd.org", "meetup.com" ])
+{
+	fileinto "Mailing lists";
+}
+elsif address :is :domain "from" [ "paypal.co.il", "paypal.com", "*.paypal.co.il", "*.paypal.com" ]
+{
+	fileinto "PayPal";
+}
+elsif address :is :domain "from" [ "amazon.com", "*.amazon.com" ]
+{
+	fileinto "Amazon";
+}
+elsif anyof (address :is :domain "from" [ "travelbird.be", "nitzan-hr.com", "ispc.co.il", "meckano.co.il", "kustonline.be", "freefax.co.il", "summary.com", "twoomail.com", "thephonehouse.es", "*.thephonehouse.es" ],
+	address :is "from" [ "rsnc.office@gmail.com", "zelba100@gmail.com" ])
+{
+	fileinto "Junk";
+}
+elsif address :is :domain "from" [ "migdal.co.il", "bezeqint.co.il", "youphone.co.il", "bezeq.co.il", "bezeqint.net", "icount.co.il", "kali.co.il", "ari-ins.co.il", "altshul.co.il", "*.migdal.co.il", "moran-fin.com" ]
+{
+	fileinto "Saved";
+}
+elsif address :is :domain "from" [ "unilink.co.il", "malam.com" ]
+{
+	fileinto "Unilink";
+}
+elsif anyof (address :is "from" [ "or.siniminis@gmail.com", "hastudio.theater@gmail.com", "hastudiotheatre@gmail.com" ],
+	address :is :domain "from" "ayalagroup.co.il")
+{
+	setflag "\\seen";
+	fileinto "Cinematheque";
+}
+elsif address :is :domain "from" [ "startcom.org", "davidcpa.co.il" ]
+{
+	fileinto "Shore";
+}
+elsif address :is :domain "from" "bigpanda.io"
+{
+	fileinto "bigpanda";
+}
+elsif address :is :domain "from" [ "wiser.com", "wisepricer.com" ]
+{
+	fileinto "Wiser";
+}
+elsif address :is :domain "from" [ "scaleway.com", "*.scaleway.com", "online.net", "*.online.net" ]
+{
+	fileinto "scaleway";
+}
+elsif address :is :domain "from" [ "spot.im" ]
+{
+	fileinto "spot.im";
+}
+elsif address :is :domain "from" [ "ebay.com", "*.ebay.com", "ebay.co.il", "*.ebay.co.il" ]
+{
+	fileinto "ebay";
+}
+elsif anyof (address :is :domain "from" [ "endlessm.com", "*.endlessm.com" ], address :is "to" "nimrod@endlessm.com")
+{
+	fileinto "Endless";
+}
+elsif address :is "to" [ "abuse@shore.co.il", "clamav@shore.co.il", "ftp@shore.co.il", "hostmaster@shore.co.il", "mailer-daemon@shore.co.il", "news@shore.co.il", "nobody@shore.co.il", "noc@shore.co.il", "postmaster@shore.co.il", "root@shore.co.il", "security@shore.co.il", "usenet@shore.co.il", "webmaster@shore.co.il", "www@shore.co.il" ]
+{
+	fileinto "Root";
+}
+elsif address :is :domain "from" [ "studentsvillage.org" ]
+{
+	fileinto "StudentVillage";
+}
+elsif address :is :domain "from" [ "google.com", "*.google.com" ]
+{
+	fileinto "Google";
+}
+elsif address :is :domain "from" [ "leumi.co.il", "*.leumi.co.il", "leumi-card.co.il", "*.leumi-card.co.il", "leumicard.co.il", "*.leumicard.co.il" ]
+{
+    fileinto "Leumi";
+}
diff --git a/dovecot/patch.diff b/dovecot/patch.diff
new file mode 100644
index 0000000000000000000000000000000000000000..992e94c19d467e32e502be8d7cc134b73f7f67fe
--- /dev/null
+++ b/dovecot/patch.diff
@@ -0,0 +1,183 @@
+--- conf.d/10-auth.conf	2019-01-23 12:05:58.000000000 +0200
++++ conf.d/10-auth.conf	2019-03-04 11:54:04.477652365 +0200
+@@ -48,7 +48,7 @@
+ # the standard variables here, eg. %Lu would lowercase the username, %n would
+ # drop away the domain if it was given, or "%n-AT-%d" would change the '@' into
+ # "-AT-". This translation is done after auth_username_translation changes.
+-#auth_username_format = %Lu
++auth_username_format = %Ln
+
+ # If you want to allow master users to log in by specifying the master
+ # username within the normal username string (ie. not using SASL mechanism's
+@@ -119,9 +119,9 @@
+ #!include auth-deny.conf.ext
+ #!include auth-master.conf.ext
+
+-!include auth-system.conf.ext
++#!include auth-system.conf.ext
+ #!include auth-sql.conf.ext
+-#!include auth-ldap.conf.ext
++!include auth-ldap.conf.ext
+ #!include auth-passwdfile.conf.ext
+ #!include auth-checkpassword.conf.ext
+ #!include auth-vpopmail.conf.ext
+--- conf.d/10-mail.conf	2019-03-04 11:47:29.000000000 +0200
++++ conf.d/10-mail.conf	2019-03-04 11:55:06.813149374 +0200
+@@ -27,7 +27,7 @@
+ #
+ # <doc/wiki/MailLocation.txt>
+ #
+-mail_location = mbox:~/mail:INBOX=/var/mail/%u
++mail_location = mbox:/var/mail/%Ln:INBOX=/var/mail/%Ln/Inbox
+
+ # If you need to set multiple mailbox locations or want to change default
+ # namespace settings, you can do it by defining namespace sections.
+--- conf.d/10-ssl.conf	2019-03-04 11:47:29.000000000 +0200
++++ conf.d/10-ssl.conf	2019-03-04 11:53:30.871608777 +0200
+@@ -57,6 +57,7 @@
+ #ssl_cipher_list = ALL:!kRSA:!SRP:!kDHd:!DSS:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK:!RC4:!ADH:!LOW@STRENGTH
+ # To disable non-EC DH, use:
+ #ssl_cipher_list = ALL:!DH:!kRSA:!SRP:!kDHd:!DSS:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK:!RC4:!ADH:!LOW@STRENGTH
++ssl_cipher_list=!kRSA:!3DES:!RC4:!DES:!MD5:!aNULL:!NULL:AESGCM+ECDH:AES256+ECDH:AES128:+SHA1
+
+ # Colon separated list of elliptic curves to use. Empty value (the default)
+ # means use the defaults from the SSL library. P-521:P-384:P-256 would be an
+--- conf.d/20-lmtp.conf	2019-01-23 12:05:58.000000000 +0200
++++ conf.d/20-lmtp.conf	2019-03-04 13:25:51.061844327 +0200
+@@ -20,6 +20,12 @@
+ # when a mail has multiple recipients.
+ #lmtp_hdr_delivery_address = final
+
++recipient_delimiter =+
++lmtp_save_to_detail_mailbox = yes
++lda_mailbox_autocreate = yes
++lda_mailbox_autosubscribe = yes
++
++
+ protocol lmtp {
+   # Space separated list of plugins to load (default is global mail_plugins).
+   #mail_plugins = $mail_plugins
+--- conf.d/90-sieve.conf	2019-03-05 21:15:58.905790954 +0200
++++ conf.d/90-sieve.conf	2019-03-05 21:19:18.160059384 +0200
+@@ -36,7 +36,7 @@
+   # active script symlink is located.
+   # For other types: use the ';name=' parameter to specify the name of the
+   # default/active script.
+-  sieve = file:~/sieve;active=~/.dovecot.sieve
++  sieve = /var/lib/dovecot/sieve.d/%Ln.sieve
+
+   # The default Sieve script when the user has none. This is the location of a
+   # global sieve script file, which gets executed ONLY if user's personal Sieve
+@@ -73,7 +73,7 @@
+   # to the script execution sequence in the specified order. Reading the
+   # numbered sieve_before settings stops at the first missing setting, so no
+   # numbers may be skipped.
+-  #sieve_before = /var/lib/dovecot/sieve.d/
++  sieve_before = /var/lib/dovecot/sieve.d/before.sieve
+   #sieve_before2 = ldap:/etc/sieve-ldap.conf;name=ldap-domain
+   #sieve_before3 = (etc...)
+
+--- conf.d/10-logging.conf	2019-03-05 21:43:01.097279575 +0200
++++ conf.d/10-logging.conf	2019-03-05 22:17:49.041027765 +0200
+@@ -4,7 +4,7 @@
+
+ # Log file to use for error messages. "syslog" logs to syslog,
+ # /dev/stderr logs to stderr.
+-#log_path = syslog
++log_path = /dev/stderr
+
+ # Log file to use for informational messages. Defaults to log_path.
+ #info_log_path =
+@@ -41,7 +41,7 @@
+ #log_core_filter =
+
+ # Log unsuccessful authentication attempts and the reasons why they failed.
+-#auth_verbose = no
++auth_verbose = yes
+
+ # In case of password mismatches, log the attempted password. Valid values are
+ # no, plain and sha1. sha1 can be useful for detecting brute force password
+--- dovecot.conf	2019-04-29 23:35:05.000000000 +0300
++++ dovecot.conf	2019-05-12 00:20:17.908388214 +0300
+@@ -75,7 +75,7 @@
+ # Space separated list of environment variables that are preserved on Dovecot
+ # startup and passed down to all of its child processes. You can also give
+ # key=value pairs to always set specific settings.
+-#import_environment = TZ
++import_environment = $import_environment LDAP_URIS LDAP_BASEDN
+
+ ##
+ ## Dictionary server settings
+--- dovecot-ldap.conf.ext	2019-01-23 12:05:58.000000000 +0200
++++ dovecot-ldap.conf.ext	2019-06-29 19:09:54.704490949 +0300
+@@ -21,7 +21,7 @@
+ 
+ # LDAP URIs to use. You can use this instead of hosts list. Note that this
+ # setting isn't supported by all LDAP libraries.
+-#uris = 
++uris = %{env:LDAP_URIS}
+ 
+ # Distinguished Name - the username used to login to the LDAP server.
+ # Leave it commented out to bind anonymously (useful with auth_bind=yes).
+@@ -66,7 +66,7 @@
+ # The pass_filter is used to find the DN for the user. Note that the pass_attrs
+ # is still used, only the password field is ignored in it. Before doing any
+ # search, the binding is switched back to the default DN.
+-#auth_bind = no
++auth_bind = yes
+ 
+ # If authentication binding is used, you can save one LDAP request per login
+ # if users' DN can be specified with a common template. The template can use
+@@ -89,7 +89,7 @@
+ 
+ # LDAP base. %variables can be used here.
+ # For example: dc=mail, dc=example, dc=org
+-base =
++base = %{env:LDAP_BASEDN}
+ 
+ # Dereference: never, searching, finding, always
+ #deref = never
+@@ -127,8 +127,8 @@
+ # userdb prefetch instead of userdb ldap in dovecot.conf. In that case you'll
+ # also have to include user_attrs in pass_attrs field prefixed with "userdb_"
+ # string. For example:
+-#pass_attrs = uid=user,userPassword=password,\
+-#  homeDirectory=userdb_home,uidNumber=userdb_uid,gidNumber=userdb_gid
++pass_attrs = uid=user,userPassword=password,\
++  homeDirectory=userdb_home,uidNumber=userdb_uid,gidNumber=userdb_gid
+ 
+ # Filter for password lookups
+ #pass_filter = (&(objectClass=posixAccount)(uid=%u))
+--- conf.d/10-master.conf	2019-06-30 15:30:20.955944241 +0300
++++ conf.d/10-master.conf	2019-06-30 15:30:20.959944142 +0300
+@@ -19,8 +19,8 @@
+     #port = 143
+   }
+   inet_listener imaps {
+-    #port = 993
+-    #ssl = yes
++    port = 993
++    ssl = yes
+   }
+ 
+   # Number of connections to handle before starting a new process. Typically
+@@ -53,15 +53,15 @@
+ 
+ service lmtp {
+   unix_listener lmtp {
+-    #mode = 0666
++    mode = 0666
+   }
+ 
+   # Create inet listener only if you can't use the above UNIX socket
+-  #inet_listener lmtp {
++  inet_listener lmtp {
+     # Avoid making LMTP visible for the entire internet
+     #address =
+-    #port = 
+-  #}
++    port = 25
++  }
+ }
+ 
+ service imap {