diff --git a/src/lib-sieve/plugins/vnd.dovecot/report/Makefile.am b/src/lib-sieve/plugins/vnd.dovecot/report/Makefile.am
index 599765f0aae72aeb769394d9d20fc429ae4a76cf..c473aa0979ec6569a112a70aeab2aef1304cf63d 100644
--- a/src/lib-sieve/plugins/vnd.dovecot/report/Makefile.am
+++ b/src/lib-sieve/plugins/vnd.dovecot/report/Makefile.am
@@ -10,8 +10,10 @@ commands = \
 
 libsieve_ext_vnd_report_la_SOURCES = \
 	ext-vnd-report.c \
+	ext-vnd-report-settings.c \
 	ext-vnd-report-common.c \
 	$(commands)
 
 noinst_HEADERS = \
+	ext-vnd-report-settings.h \
 	ext-vnd-report-common.h
diff --git a/src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c b/src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
index 11a09bb05aa2959bac735c5800a24629ede493db..b56eeb87506308d90ba48c894fd91cf9e75af3b1 100644
--- a/src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+++ b/src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
@@ -453,7 +453,7 @@ act_report_send(const struct sieve_action_exec_env *aenv,
 	struct sieve_message_context *msgctx = aenv->msgctx;
 	const struct sieve_script_env *senv = eenv->scriptenv;
 	const struct sieve_message_data *msgdata = eenv->msgdata;
-	struct sieve_address_source report_from = extctx->report_from;
+	struct sieve_address_source report_from = extctx->set->parsed.from;
 	const struct smtp_address *sender, *user;
 	struct sieve_smtp_context *sctx;
 	struct istream *input;
diff --git a/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.c b/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.c
index 543b5c6b8a7ea5d9252fd40a4768f3d83aaa9344..47947ba97f1f1bf6629810a293a66c10f2eaa0e1 100644
--- a/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.c
+++ b/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.c
@@ -3,6 +3,7 @@
 
 #include "lib.h"
 #include "str.h"
+#include "settings.h"
 #include "rfc822-parser.h"
 
 #include "sieve-common.h"
@@ -14,17 +15,32 @@ int ext_report_load(const struct sieve_extension *ext, void **context_r)
 {
 	struct sieve_instance *svinst = ext->svinst;
 	struct ext_report_context *extctx;
+	const struct ext_report_settings *set;
+	const char *error;
 
-	extctx = p_new(svinst->pool, struct ext_report_context, 1);
+	if (settings_get(svinst->event, &ext_report_setting_parser_info, 0,
+			 &set, &error) < 0) {
+		e_error(svinst->event, "%s", error);
+		return -1;
+	}
 
-	(void)sieve_address_source_parse_from_setting(
-		svinst, svinst->pool, "sieve_report_from",
-		&extctx->report_from);
+	extctx = i_new(struct ext_report_context, 1);
+	extctx->set = set;
 
 	*context_r = extctx;
 	return 0;
 }
 
+void ext_report_unload(const struct sieve_extension *ext)
+{
+	struct ext_report_context *extctx = ext->context;
+
+	if (extctx == NULL)
+		return;
+	settings_free(extctx->set);
+	i_free(extctx);
+}
+
 const char *ext_vnd_report_parse_feedback_type(const char *feedback_type)
 {
 	struct rfc822_parser_context parser;
diff --git a/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.h b/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.h
index 6302a7e759e61259957f78bf464474ae48abf79b..1e45d1f323408c9d9c7d25b71c1b0d8153c0440a 100644
--- a/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.h
+++ b/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-common.h
@@ -1,12 +1,14 @@
 #ifndef EXT_REPORT_COMMON_H
 #define EXT_REPORT_COMMON_H
 
+#include "ext-vnd-report-settings.h"
+
 /*
  * Extension configuration
  */
 
 struct ext_report_context {
-	struct sieve_address_source report_from;
+	const struct ext_report_settings *set;
 };
 
 /*
@@ -16,6 +18,7 @@ struct ext_report_context {
 extern const struct sieve_extension_def vnd_report_extension;
 
 int ext_report_load(const struct sieve_extension *ext, void **context_r);
+void ext_report_unload(const struct sieve_extension *ext);
 
 /*
  * Commands
diff --git a/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-settings.c b/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-settings.c
new file mode 100644
index 0000000000000000000000000000000000000000..89b93d771c5435ee47fec9bf21458359395d6dab
--- /dev/null
+++ b/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-settings.c
@@ -0,0 +1,57 @@
+/* Copyright (c) 2024 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "array.h"
+#include "settings.h"
+#include "settings-parser.h"
+
+#include "ext-vnd-report-settings.h"
+
+static bool
+ext_report_settings_check(void *_set, pool_t pool, const char **error_r);
+
+#undef DEF
+#define DEF(type, name) \
+	SETTING_DEFINE_STRUCT_##type("sieve_report_"#name, name, \
+				     struct ext_report_settings)
+
+static const struct setting_define ext_report_setting_defines[] = {
+	DEF(STR, from),
+
+	SETTING_DEFINE_LIST_END,
+};
+
+static const struct ext_report_settings ext_report_default_settings = {
+	.from = "",
+};
+
+const struct setting_parser_info ext_report_setting_parser_info = {
+	.name = "sieve_report",
+
+	.defines = ext_report_setting_defines,
+	.defaults = &ext_report_default_settings,
+
+	.struct_size = sizeof(struct ext_report_settings),
+
+	.check_func = ext_report_settings_check,
+
+	.pool_offset1 = 1 + offsetof(struct ext_report_settings, pool),
+};
+
+/* <settings checks> */
+static bool
+ext_report_settings_check(void *_set, pool_t pool, const char **error_r)
+{
+	struct ext_report_settings *set = _set;
+
+	if (!sieve_address_source_parse(pool, set->from, &set->parsed.from)) {
+		*error_r = t_strdup_printf("sieve_report_from: "
+					   "Invalid address source '%s'",
+					   set->from);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+/* </settings checks> */
diff --git a/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-settings.h b/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-settings.h
new file mode 100644
index 0000000000000000000000000000000000000000..d71f4c4d4f78e256f6d1ffd441ff9c265595a8b7
--- /dev/null
+++ b/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report-settings.h
@@ -0,0 +1,18 @@
+#ifndef EXT_REPORT_SETTINGS_H
+#define EXT_REPORT_SETTINGS_H
+
+#include "sieve-address-source.h"
+
+struct ext_report_settings {
+	pool_t pool;
+
+	const char *from;
+
+	struct {
+		struct sieve_address_source from;
+	} parsed;
+};
+
+extern const struct setting_parser_info ext_report_setting_parser_info;
+
+#endif
diff --git a/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report.c b/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report.c
index f1cc7ce0dd7748944662382e426d6ae216a12262..90c8aaab0e279adfa787e13110dbb22dbccb3360 100644
--- a/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report.c
+++ b/src/lib-sieve/plugins/vnd.dovecot/report/ext-vnd-report.c
@@ -35,6 +35,7 @@ ext_report_validator_load(const struct sieve_extension *ext,
 const struct sieve_extension_def vnd_report_extension = {
 	.name = "vnd.dovecot.report",
 	.load = ext_report_load,
+	.unload = ext_report_unload,
 	.validator_load = ext_report_validator_load,
 	SIEVE_EXT_DEFINE_OPERATION(report_operation),
 };
diff --git a/src/lib-sieve/sieve-address-source.h b/src/lib-sieve/sieve-address-source.h
index 5a300ff7a404914462f2d1b826968b57d7f645a9..5bfd5ff7dca01bc755ef0966c7262f955a669313 100644
--- a/src/lib-sieve/sieve-address-source.h
+++ b/src/lib-sieve/sieve-address-source.h
@@ -1,9 +1,10 @@
 #ifndef SIEVE_ADDRESS_SOURCE_H
 #define SIEVE_ADDRESS_SOURCE_H
 
-#include "sieve-common.h"
-
+struct sieve_instance;
+struct sieve_script_env;
 struct sieve_message_context;
+enum sieve_execute_flags;
 
 enum sieve_address_source_type {
 	SIEVE_ADDRESS_SOURCE_DEFAULT = 0,