diff --git a/README.md b/README.md
index 21c6004a09bfed63fd0f506e8a379ee68c1d72ae..9763192bc070e4dcd6393f4d394da25e6f8eb9a8 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,12 @@ auth_mechanisms: ["plain", "login"]
 # Array of users if dovecot should handle users in a db. Not usable if you enable ldap.
 # Each user is a dict, for options see *userdict* below
 user: []
+
+# The maximum amount of storage a mailbox can use in kilobytes. Supports b/k/M/G/T/% suffixes
+quota: ""
+
+# The amount a mailbox can go over quota. Works only for accepting messages. Value in %, defaults to 10
+quota_grace: "10"
 ```
 
 **userdict**
diff --git a/defaults/main.yml b/defaults/main.yml
index 024a2e613c86ee443415861121992007f0b2a7e6..aa1815706ff0e4218d2b79bdd381079e216b9dfc 100644
--- a/defaults/main.yml
+++ b/defaults/main.yml
@@ -8,3 +8,5 @@ dovecot:
   - plain
   - login
   user: []
+  quota: ""
+  quota_grace: "10"
diff --git a/tasks/main.yml b/tasks/main.yml
index 1737ac8a7a061f6440e0ef7578e6447877139064..379903a0ca4e78173dd155dd0759212484638538 100644
--- a/tasks/main.yml
+++ b/tasks/main.yml
@@ -42,7 +42,9 @@
     - { src: "10-mail.conf.j2", dest: "/etc/dovecot/conf.d/10-mail.conf" }
     - { src: "15-lda.conf.j2", dest: "/etc/dovecot/conf.d/15-lda.conf" }
     - { src: "15-mailboxes.conf.j2", dest: "/etc/dovecot/conf.d/15-mailboxes.conf" }
+    - { src: "20-imap.conf.j2", dest: "/etc/dovecot/conf.d/20-imap.conf" }
     - { src: "20-managesieve.conf.j2", dest: "/etc/dovecot/conf.d/20-managesieve.conf" }
+    - { src: "90-quota.conf.j2", dest: "/etc/dovecot/conf.d/90-quota.conf" }
     - { src: "auth-system.conf.j2", dest: "/etc/dovecot/conf.d/auth-system.conf" }
     - { src: "auth-ldap.conf.j2", dest: "/etc/dovecot/conf.d/auth-ldap.conf" }
     - { src: "dovecot-ldap.conf.ext.j2", dest: "/etc/dovecot/dovecot-ldap.conf.ext" }
diff --git a/templates/10-mail.conf.j2 b/templates/10-mail.conf.j2
index e991cc85c637ad57b7bc47245b430e2f8a54c963..5b424ca00b1b456dad900f189d450a5dfd2a1697 100644
--- a/templates/10-mail.conf.j2
+++ b/templates/10-mail.conf.j2
@@ -212,7 +212,11 @@ last_valid_gid = {{ vmail_group.gid }}
 
 # Space separated list of plugins to load for all services. Plugins specific to
 # IMAP, LDA, etc. are added to this list in their own .conf files.
+{% if dovecot.quota %}
+mail_plugins = quota
+{% else %}
 #mail_plugins =
+{% endif %}
 
 ##
 ## Mailbox handling optimizations
diff --git a/templates/15-lda.conf.j2 b/templates/15-lda.conf.j2
index 81d36755b2ce7bbbcee68f60a85cc29de313e700..fa5f498b8d396271dff44e8bb19e7b9f7440d287 100644
--- a/templates/15-lda.conf.j2
+++ b/templates/15-lda.conf.j2
@@ -4,15 +4,19 @@
 
 # Address to use when sending rejection mails.
 # Default is postmaster@<your domain>. %d expands to recipient domain.
-#postmaster_address = 
+#postmaster_address =
 
 # Hostname to use in various parts of sent mails (e.g. in Message-Id) and
 # in LMTP replies. Default is the system's real hostname@domain.
-#hostname = 
+#hostname =
 
 # If user is over quota, return with temporary failure instead of
 # bouncing the mail.
+{% if dovecot.quota %}
+quota_full_tempfail = yes
+{% else %}
 #quota_full_tempfail = no
+{% endif %}
 
 # Binary to use for sending mails.
 #sendmail_path = /usr/sbin/sendmail
@@ -32,7 +36,7 @@
 #recipient_delimiter = +
 
 # Header where the original recipient address (SMTP's RCPT TO: address) is taken
-# from if not available elsewhere. With dovecot-lda -a parameter overrides this. 
+# from if not available elsewhere. With dovecot-lda -a parameter overrides this.
 # A commonly used header for this is X-Original-To.
 #lda_original_recipient_header =
 
diff --git a/templates/20-imap.conf.j2 b/templates/20-imap.conf.j2
new file mode 100644
index 0000000000000000000000000000000000000000..9929812f9dd78f3db7e64d5513d134b4bd98fad0
--- /dev/null
+++ b/templates/20-imap.conf.j2
@@ -0,0 +1,102 @@
+##
+## IMAP specific settings
+##
+
+# If nothing happens for this long while client is IDLEing, move the connection
+# to imap-hibernate process and close the old imap process. This saves memory,
+# because connections use very little memory in imap-hibernate process. The
+# downside is that recreating the imap process back uses some resources.
+#imap_hibernate_timeout = 0
+
+# Maximum IMAP command line length. Some clients generate very long command
+# lines with huge mailboxes, so you may need to raise this if you get
+# "Too long argument" or "IMAP command line too large" errors often.
+#imap_max_line_length = 64k
+
+# IMAP logout format string:
+#  %i - total number of bytes read from client
+#  %o - total number of bytes sent to client
+#  %{fetch_hdr_count} - Number of mails with mail header data sent to client
+#  %{fetch_hdr_bytes} - Number of bytes with mail header data sent to client
+#  %{fetch_body_count} - Number of mails with mail body data sent to client
+#  %{fetch_body_bytes} - Number of bytes with mail body data sent to client
+#  %{deleted} - Number of mails where client added \Deleted flag
+#  %{expunged} - Number of mails that client expunged, which does not
+#                include automatically expunged mails
+#  %{autoexpunged} - Number of mails that were automatically expunged after
+#                    client disconnected
+#  %{trashed} - Number of mails that client copied/moved to the
+#               special_use=\Trash mailbox.
+#  %{appended} - Number of mails saved during the session
+#imap_logout_format = in=%i out=%o deleted=%{deleted} expunged=%{expunged} \
+#  trashed=%{trashed} hdr_count=%{fetch_hdr_count} \
+#  hdr_bytes=%{fetch_hdr_bytes} body_count=%{fetch_body_count} \
+#  body_bytes=%{fetch_body_bytes}
+
+# Override the IMAP CAPABILITY response. If the value begins with '+',
+# add the given capabilities on top of the defaults (e.g. +XFOO XBAR).
+#imap_capability =
+
+# How long to wait between "OK Still here" notifications when client is
+# IDLEing.
+#imap_idle_notify_interval = 2 mins
+
+# ID field names and values to send to clients. Using * as the value makes
+# Dovecot use the default value. The following fields have default values
+# currently: name, version, os, os-version, support-url, support-email.
+#imap_id_send =
+
+# ID fields sent by client to log. * means everything.
+#imap_id_log =
+
+# Workarounds for various client bugs:
+#   delay-newmail:
+#     Send EXISTS/RECENT new mail notifications only when replying to NOOP
+#     and CHECK commands. Some clients ignore them otherwise, for example OSX
+#     Mail (<v2.1). Outlook Express breaks more badly though, without this it
+#     may show user "Message no longer in server" errors. Note that OE6 still
+#     breaks even with this workaround if synchronization is set to
+#     "Headers Only".
+#   tb-extra-mailbox-sep:
+#     Thunderbird gets somehow confused with LAYOUT=fs (mbox and dbox) and
+#     adds extra '/' suffixes to mailbox names. This option causes Dovecot to
+#     ignore the extra '/' instead of treating it as invalid mailbox name.
+#   tb-lsub-flags:
+#     Show \Noselect flags for LSUB replies with LAYOUT=fs (e.g. mbox).
+#     This makes Thunderbird realize they aren't selectable and show them
+#     greyed out, instead of only later giving "not selectable" popup error.
+#
+# The list is space-separated.
+#imap_client_workarounds =
+
+# Host allowed in URLAUTH URLs sent by client. "*" allows all.
+#imap_urlauth_host =
+
+# Enable IMAP LITERAL- extension (replaces LITERAL+)
+#imap_literal_minus = no
+
+# What happens when FETCH fails due to some internal error:
+#   disconnect-immediately:
+#     The FETCH is aborted immediately and the IMAP client is disconnected.
+#   disconnect-after:
+#     The FETCH runs for all the requested mails returning as much data as
+#     possible. The client is finally disconnected without a tagged reply.
+#   no-after:
+#     Same as disconnect-after, but tagged NO reply is sent instead of
+#     disconnecting the client. If the client attempts to FETCH the same failed
+#     mail more than once, the client is disconnected. This is to avoid clients
+#     from going into infinite loops trying to FETCH a broken mail.
+#imap_fetch_failure = disconnect-immediately
+
+protocol imap {
+  # Space separated list of plugins to load (default is global mail_plugins).
+  {% if dovecot.quota -%}
+  mail_plugins = $mail_plugins imap_quota
+  {% else -%}
+  #mail_plugins = $mail_plugins
+  {% endif -%}
+
+  # Maximum number of IMAP connections allowed for a user from each IP address.
+  # NOTE: The username is compared case-sensitively.
+  #mail_max_userip_connections = 10
+}
diff --git a/templates/90-quota.conf.j2 b/templates/90-quota.conf.j2
new file mode 100644
index 0000000000000000000000000000000000000000..d0751725001a0cc7715611071c7e6b3c2966efae
--- /dev/null
+++ b/templates/90-quota.conf.j2
@@ -0,0 +1,112 @@
+##
+## Quota configuration.
+##
+
+# Note that you also have to enable quota plugin in mail_plugins setting.
+# <doc/wiki/Quota.txt>
+
+##
+## Quota limits
+##
+
+# Quota limits are set using "quota_rule" parameters. To get per-user quota
+# limits, you can set/override them by returning "quota_rule" extra field
+# from userdb. It's also possible to give mailbox-specific limits, for example
+# to give additional 100 MB when saving to Trash:
+
+plugin {
+  {% if dovecot.quota -%}
+  quota_rule = *:storage={{ dovecot.quota }}
+
+  # What to give back to postfix when checking quotas
+  quota_status_success = DUNNO
+  quota_status_nouser = DUNNO
+  quota_status_overquota = "552 5.2.2 Mailbox is full"
+  {% else %}
+  #quota_rule = *:storage=1G
+  #quota_rule2 = Trash:storage=+100M
+  {% endif -%}
+
+  # LDA/LMTP allows saving the last mail to bring user from under quota to
+  # over quota, if the quota doesn't grow too high. Default is to allow as
+  # long as quota will stay under 10% above the limit. Also allowed e.g. 10M.
+  {% if dovecot.quota_grace -%}
+  quota_grace = {{ dovecot.quota_grace }}%%
+  {% else -%}
+  #quota_grace = 10%%
+  {% endif %}
+
+  # Quota plugin can also limit the maximum accepted mail size.
+  #quota_max_mail_size = 100M
+}
+
+##
+## Quota warnings
+##
+
+# You can execute a given command when user exceeds a specified quota limit.
+# Each quota root has separate limits. Only the command for the first
+# exceeded limit is executed, so put the highest limit first.
+# The commands are executed via script service by connecting to the named
+# UNIX socket (quota-warning below).
+# Note that % needs to be escaped as %%, otherwise "% " expands to empty.
+
+plugin {
+  #quota_warning = storage=95%% quota-warning 95 %u
+  #quota_warning2 = storage=80%% quota-warning 80 %u
+}
+
+# Example quota-warning service. The unix listener's permissions should be
+# set in a way that mail processes can connect to it. Below example assumes
+# that mail processes run as vmail user. If you use mode=0666, all system users
+# can generate quota warnings to anyone.
+#service quota-warning {
+#  executable = script /usr/local/bin/quota-warning.sh
+#  user = dovecot
+#  unix_listener quota-warning {
+#    user = vmail
+#  }
+#}
+
+##
+## Quota backends
+##
+
+# Multiple backends are supported:
+#   dirsize: Find and sum all the files found from mail directory.
+#            Extremely SLOW with Maildir. It'll eat your CPU and disk I/O.
+#   dict: Keep quota stored in dictionary (eg. SQL)
+#   maildir: Maildir++ quota
+#   fs: Read-only support for filesystem quota
+
+plugin {
+  #quota = dirsize:User quota
+  {% if dovecot.quota -%}
+  quota = maildir:User quota
+  {% else -%}
+  #quota = maildir:User quota
+  {% endif -%}
+  #quota = dict:User quota::proxy::quota
+  #quota = fs:User quota
+}
+
+# Multiple quota roots are also possible, for example this gives each user
+# their own 100MB quota and one shared 1GB quota within the domain:
+plugin {
+  #quota = dict:user::proxy::quota
+  #quota2 = dict:domain:%d:proxy::quota_domain
+  #quota_rule = *:storage=102400
+  #quota2_rule = *:storage=1048576
+}
+
+{% if dovecot.quota %}
+# add a service so that postfix can check quota when receiving mail
+service quota-status {
+  executable = quota-status -p postfix
+  inet_listener {
+    address = 127.0.0.1
+    port = 12340
+  }
+  client_limit = 1
+}
+{% endif %}