Lazy Expunge¶
The lazy expunge plugin provides a “second-chance” to recover messages that would otherwise be deleted from a mailbox by user action.
It does this by moving the message to a defined location (either a mailbox, or a namespace – see below for further details) when a user deletes the message from a mailbox.
This behavior is useful for a variety of reasons:
Protect against misconfigured clients (e.g. POP3 client that deletes all messages)
Protect against accidental deletion (user error)
Archiving
Generally, lazy-expunge is configured so that the expunged mails are not counted in the user’s quota. Unless being used for archiving, autoexpunge should be used to prune the mailbox to control storage usage.
Settings¶
See lazy-expunge plugin.
Configuration¶
Storage Locations¶
mailbox¶
New in version v2.2.24.
Messages that are expunged are moved to a single mailbox.
This is the simplest configuration. The mailbox is created automatically.
You probably also want to hide it with an ACL from the user, if recovery is only expected to be an action performed by an admin/operator.
To move to a mailbox, do NOT add a trailing delimiter to the
lazy_expunge
setting.
Example configuration:
namespace inbox {
mailbox .EXPUNGED {
autoexpunge = 7days
autoexpunge_max_mails = 100000
}
}
mail_plugins = $mail_plugins lazy_expunge acl
plugin {
# Move messages to an .EXPUNGED mailbox
lazy_expunge = .EXPUNGED
# Define ACL so that user cannot list the .EXPUNGED mailbox
acl = vfile:/etc/dovecot/dovecot.acl
# Expunged messages most likely don't want to be included in quota:
quota_rule = .EXPUNGED:ignore
}
Where /etc/dovecot/dovecot.acl
contains:
.EXPUNGED owner rwstipekxa
You could also leave the permissions empty if you don’t want to allow clients to access it at all.
namespace¶
Deprecated since version v2.3.0.
Expunged messages are moved to mailbox(es) within a defined namespace
When a message is expunged from mailbox <name>
, it’s moved to a mailbox
<name>
in the expunge namespace. When an entire mailbox <name>
is
deleted, it’s moved to this namespace as <name>
. If the mailbox already
exists in the expunge namespace, the contents are merged.
To move to a namespace, you MUST add a trailing delimiter to the
lazy_expunge
argument. Example: if the namespace delimiter is /
,
and you want to move to the .EXPUNGED
namespace, then the
lazy_expunge
setting should be set to
.EXPUNGED/
.
Example configuration:
# Default namespace
namespace {
prefix =
separator = /
inbox = yes
}
# Namespace for lazy_expunge plugin
namespace {
prefix = .EXPUNGED/
hidden = yes
list = no
separator = /
location = maildir:~/Maildir/expunged
}
mail_plugins = $mail_plugins lazy_expunge
plugin {
# Move expunged messages into the .EXPUNGED namespace
lazy_expunge = .EXPUNGED/
}
mdbox¶
With mdbox <dbox_mbox_format>, use different
MAILBOXDIRs
(so copying between namespaces works quickly within the same
storage), but otherwise exactly the same paths (INDEX
, control
):
# Default namespace
namespace {
prefix =
inbox = yes
location = mdbox:~/mdbox:INDEX=/var/index/%d/%n
separator = /
}
# lazy_expunge namespace(s)
namespace {
prefix = .EXPUNGED/
hidden = yes
list = no
separator = /
subscriptions = no
location = mdbox:~/mdbox:INDEX=/var/index/%d/%n:MAILBOXDIR=expunged
# If mailbox_list_index=yes is enabled, it needs a separate index file
# (v2.2.28+):
#location = mdbox:~/mdbox:INDEX=/var/index/%d/%n:MAILBOXDIR=expunged:LISTINDEX=expunged.list.index
}
Copy Only the Last Instance¶
If a mail has multiple copies within a user account, each copy is normally moved to the lazy expunge storage when it’s expunged.
Example: this may happen when moving a message to Trash, as clients can issue IMAP COPY command to copy the message to Trash before expunging the message from the original mailbox. Deleting later from Trash would result in two copies of the same message in the lazy expunge storage.
With v2.2+ you can enable
lazy_expunge_only_last_instance
to copy
only the last instance to the expunge storage. This ensures that only a single
copy of a message will appear in the expunge storage.
Note that this feature only works with certain storage setups; see
lazy_expunge_only_last_instance
for the
list of supported storages.
Quota¶
Generally, it is desired that messages in expunge storage are NOT counted towards user quota, as the messages seen by the user will not match-up with the size of the quota otherwise (especially if expunge storage is hidden from users via ACL).
Example to exclude expunge storage from the quota:
plugin {
quota = count:User quota
quota_rule = *:storage=1GB
# Exclude .EXPUNGED mailbox from the quota
quota_rule2 = .EXPUNGED:ignore
}
See Quota Plugin.
Cleaning up¶
doveadm¶
Doveadm can be used to manually clean expunge storage.
Example to delete all messages in .EXPUNGED
namespace older than one day:
doveadm expunge mailbox '.EXPUNGED/*' savedsince 1d
autoexpunge¶
Set autoexpunge configuration for expunge storage to automatically clean old messages.
See Namespaces.
Obox Settings¶
Lazy expunge allows reduction of Cassandra dictmap lookups by removing the
lockdir setting and enabling the obox_track_copy_flags
setting.
mail_plugins = $mail_plugins lazy_expunge
plugin {
lazy_expunge = .EXPUNGED
# If Cassandra w/obox is used:
obox_track_copy_flags = yes
}
Dumpster¶
See Dumpster Config for information on how to configure lazy_expunge with the OX Dumpster module.