diff --git a/src/lib-sieve/plugins/vacation/cmd-vacation.c b/src/lib-sieve/plugins/vacation/cmd-vacation.c
index 9aa77de60b885e7388e132c3c204a873a2fb5d3a..62f87a00df34fd7e474dedc8803cebb9d6feb6d1 100644
--- a/src/lib-sieve/plugins/vacation/cmd-vacation.c
+++ b/src/lib-sieve/plugins/vacation/cmd-vacation.c
@@ -1017,8 +1017,8 @@ _get_var_expand_table(const struct sieve_action_exec_env *aenv ATTR_UNUSED,
 		      const char *subject)
 {
 	const struct var_expand_table stack_tab[] = {
-		{ '$', subject, "subject" },
-		{ '\0', NULL, NULL }
+		{ .key = "subject", .value = subject },
+		VAR_EXPAND_TABLE_END
 	};
 
 	return p_memdup(unsafe_data_stack_pool, stack_tab, sizeof(stack_tab));
@@ -1033,7 +1033,6 @@ act_vacation_get_default_subject(const struct sieve_action_exec_env *aenv,
 	const struct sieve_message_data *msgdata = eenv->msgdata;
 	const char *header, *error;
 	string_t *str;
-	const struct var_expand_table *tab;
 	int ret;
 
 	*subject_r = (config->default_subject == NULL ?
@@ -1052,9 +1051,11 @@ act_vacation_get_default_subject(const struct sieve_action_exec_env *aenv,
 	}
 
 	str = t_str_new(256);
-	tab = _get_var_expand_table(aenv, header);
-	if (var_expand_with_table(str, config->default_subject_template,
-				  tab, &error) <= 0) {
+	const struct var_expand_params params = {
+		.table = _get_var_expand_table(aenv, header),
+	};
+	if (var_expand(str, config->default_subject_template, &params,
+		       &error) < 0) {
 		e_error(aenv->event,
 			"Failed to expand deliver_log_format=%s: %s",
 			config->default_subject_template, error);
diff --git a/src/lib-sieve/storage/ldap/sieve-ldap-db.c b/src/lib-sieve/storage/ldap/sieve-ldap-db.c
index 5432c65e98fc488d9630ddb3c6bc095fdc96f4ec..3fa2085e9fdcb85b7db4758c173aee5e7d61792a 100644
--- a/src/lib-sieve/storage/ldap/sieve-ldap-db.c
+++ b/src/lib-sieve/storage/ldap/sieve-ldap-db.c
@@ -1172,12 +1172,12 @@ sieve_ldap_db_get_script(struct ldap_connection *conn,
 
 const struct var_expand_table
 auth_request_var_expand_static_tab[] = {
-	{ 'u', NULL, "user" },
-	{ 'n', NULL, "username" },
-	{ 'd', NULL, "domain" },
-	{ 'h', NULL, "home" },
-	{ '\0', NULL, "name" },
-	{ '\0', NULL, NULL }
+	{ .key = "user", .value = NULL },
+	{ .key = "username", .value = NULL },
+	{ .key = "domain", .value = NULL },
+	{ .key = "home", .value = NULL },
+	{ .key = "name", .value = NULL },
+	VAR_EXPAND_TABLE_END
 };
 
 static const struct var_expand_table *
@@ -1252,7 +1252,6 @@ int sieve_ldap_db_lookup_script(struct ldap_connection *conn,
 	struct sieve_storage *storage = &lstorage->storage;
 	const struct sieve_ldap_storage_settings *set = &lstorage->set;
 	struct sieve_ldap_script_lookup_request *request;
-	struct var_expand_params params;
 	char **attr_names;
 	const char *error;
 	string_t *str;
@@ -1262,10 +1261,12 @@ int sieve_ldap_db_lookup_script(struct ldap_connection *conn,
 	request = p_new(pool, struct sieve_ldap_script_lookup_request, 1);
 	request->request.pool = pool;
 
-	params.table = db_ldap_get_var_expand_table(conn, name);
+	const struct var_expand_params params = {
+		.table = db_ldap_get_var_expand_table(conn, name),
+	};
 
 	str = t_str_new(512);
-	if (var_expand(str, set->base, &params, &error) <= 0) {
+	if (var_expand(str, set->base, &params, &error) < 0) {
 		e_error(storage->event, "db: "
 			"Failed to expand base=%s: %s",
 			set->base, error);
@@ -1277,7 +1278,7 @@ int sieve_ldap_db_lookup_script(struct ldap_connection *conn,
 	attr_names[0] = p_strdup(pool, set->sieve_ldap_mod_attr);
 
 	str_truncate(str, 0);
-	if (var_expand(str, set->sieve_ldap_filter, &params, &error) <= 0) {
+	if (var_expand(str, set->sieve_ldap_filter, &params, &error) < 0) {
 		e_error(storage->event, "db: "
 			"Failed to expand sieve_ldap_filter=%s: %s",
 			set->sieve_ldap_filter, error);
diff --git a/src/managesieve/managesieve-client.c b/src/managesieve/managesieve-client.c
index e144fda480bc76133b68c4174be971adec4ac23e..9a556ee78ed05e4d50cfda80c05ebd139cae0523 100644
--- a/src/managesieve/managesieve-client.c
+++ b/src/managesieve/managesieve-client.c
@@ -194,39 +194,47 @@ void client_create_finish(struct client *client)
 static const char *client_stats(struct client *client)
 {
 	const struct var_expand_table logout_tab[] = {
-		{ 'i', dec2str(i_stream_get_absolute_offset(client->input)),
-		  "input" },
-		{ 'o', dec2str(client->output->offset), "output" },
-		{ '\0', dec2str(client->put_bytes), "put_bytes" },
-		{ '\0', dec2str(client->put_count), "put_count" },
-		{ '\0', dec2str(client->get_bytes), "get_bytes" },
-		{ '\0', dec2str(client->get_count), "get_count" },
-		{ '\0', dec2str(client->check_bytes), "check_bytes" },
-		{ '\0', dec2str(client->check_count), "check_count" },
-		{ '\0', dec2str(client->deleted_count), "deleted_count" },
-		{ '\0', dec2str(client->renamed_count), "renamed_count" },
-		{ '\0', client->session_id, "session" },
-		{ '\0', NULL, NULL }
+		{
+			.key = "input",
+			.value = dec2str(i_stream_get_absolute_offset(client->input)),
+		},
+		{ .key = "output", .value = dec2str(client->output->offset) },
+		{ .key = "put_bytes", .value = dec2str(client->put_bytes) },
+		{ .key = "put_count", .value = dec2str(client->put_count) },
+		{ .key = "get_bytes", .value = dec2str(client->get_bytes) },
+		{ .key = "get_count", .value = dec2str(client->get_count) },
+		{ .key = "check_bytes", .value = dec2str(client->check_bytes) },
+		{ .key = "check_count", .value = dec2str(client->check_count) },
+		{ .key = "deleted_count", .value = dec2str(client->deleted_count) },
+		{ .key = "renamed_count", .value = dec2str(client->renamed_count) },
+		{ .key = "session", .value = client->session_id },
+		VAR_EXPAND_TABLE_END
+	};
+	const struct var_expand_params *user_params =
+		mail_user_var_expand_params(client->user);
+	const struct var_expand_params params = {
+		.tables_arr = (const struct var_expand_table*[]){
+			logout_tab,
+			user_params->table,
+			NULL
+		},
+		.providers = user_params->providers,
+		.context = user_params->context,
 	};
-	const struct var_expand_table *user_tab =
-		mail_user_var_expand_table(client->user);
-	const struct var_expand_table *tab =
-		t_var_expand_merge_tables(logout_tab, user_tab);
 	string_t *str;
 	const char *error;
 
+	event_add_int(client->event, "net_in_bytes", i_stream_get_absolute_offset(client->input));
+	event_add_int(client->event, "net_out_bytes", client->output->offset);
+
 	str = t_str_new(128);
-	if (var_expand_with_funcs(str, client->set->managesieve_logout_format,
-				  tab, mail_user_var_expand_func_table,
-				  client->user, &error) < 0) {
+	if (var_expand(str, client->set->managesieve_logout_format,
+			   &params, &error) < 0) {
 		e_error(client->event,
 			"Failed to expand managesieve_logout_format=%s: %s",
 			client->set->managesieve_logout_format, error);
 	}
 
-	event_add_int(client->event, "net_in_bytes", i_stream_get_absolute_offset(client->input));
-	event_add_int(client->event, "net_out_bytes", client->output->offset);
-
 	return str_c(str);
 }
 
diff --git a/src/managesieve/managesieve-settings.c b/src/managesieve/managesieve-settings.c
index eebe6dde221a2a6c2759da802bfcc229289e8592..eeb086ced60ffb1d9381aaaf1f2f45e29442a11e 100644
--- a/src/managesieve/managesieve-settings.c
+++ b/src/managesieve/managesieve-settings.c
@@ -81,7 +81,7 @@ static struct managesieve_settings managesieve_default_settings = {
 	.managesieve_max_line_length = 65536,
 	.managesieve_implementation_string = DOVECOT_NAME " " PIGEONHOLE_NAME,
 	.managesieve_client_workarounds = "",
-	.managesieve_logout_format = "bytes=%i/%o",
+	.managesieve_logout_format = "bytes=%{input}/%{output}",
 	.managesieve_max_compile_errors = 5
 };
 
diff --git a/src/plugins/lda-sieve/lda-sieve-plugin.c b/src/plugins/lda-sieve/lda-sieve-plugin.c
index bc688ba2d6490c3b84dd1977b376ac9ac3014bcd..897af08e873e75898eff5ca8329dafce1001f057 100644
--- a/src/plugins/lda-sieve/lda-sieve-plugin.c
+++ b/src/plugins/lda-sieve/lda-sieve-plugin.c
@@ -207,15 +207,16 @@ lda_sieve_result_amend_log_message(const struct sieve_script_env *senv,
 				   const char *message)
 {
 	struct mail_deliver_context *mdctx = senv->script_context;
-	const struct var_expand_table *table;
 	string_t *str;
 	const char *error;
 
-	table = mail_deliver_ctx_get_log_var_expand_table(mdctx, message);
+	const struct var_expand_params params = {
+		.table = mail_deliver_ctx_get_log_var_expand_table(mdctx, message),
+	};
 
 	str = t_str_new(256);
-	if (var_expand_with_table(str, mdctx->set->deliver_log_format,
-				  table, &error) <= 0) {
+	if (var_expand(str, mdctx->set->deliver_log_format, &params,
+		       &error) < 0) {
 		e_error(mdctx->event,
 			"Failed to expand deliver_log_format=%s: %s",
 			mdctx->set->deliver_log_format, error);
diff --git a/tests/extensions/vacation/message.svtest b/tests/extensions/vacation/message.svtest
index ef8c957c4db7d70c381a2ec292c76beb66de3d06..b61c34b3bca651a5e24306c2d4dddf13935ab39a 100644
--- a/tests/extensions/vacation/message.svtest
+++ b/tests/extensions/vacation/message.svtest
@@ -91,38 +91,6 @@ test "Subject - configured, no subject" {
 	}
 }
 
-/*
- * Subject - configured
- */
-
-test_set "message" text:
-From: stephan@example.org
-Subject: Bloemetjes
-To: nico@frop.example.org
-
-Frop
-.
-;
-
-test_config_set "sieve_vacation_default_subject_template"
-	"Automatisch bericht: %$";
-test_config_reload :extension "vacation";
-
-test_result_reset;
-test "Subject - configured" {
-	vacation "I am not in today!";
-
-	if not test_result_execute {
-		test_fail "execution of result failed";
-	}
-
-	test_message :smtp 0;
-
-	if not header :is "subject" "Automatisch bericht: Bloemetjes" {
-		test_fail "Subject header is incorrect";
-	}
-}
-
 /*
  * Subject - configured, full variable
  */