diff --git a/configure.ac b/configure.ac
index 53b3359f6373f2c5f51f050f9e68fc9898986449..091973e952a89ad3579526036554a280fc6bb0be 100644
--- a/configure.ac
+++ b/configure.ac
@@ -184,6 +184,7 @@ src/Makefile
 src/lib-sieve/Makefile
 src/lib-sieve/util/Makefile
 src/lib-sieve/storage/Makefile
+src/lib-sieve/storage/data/Makefile
 src/lib-sieve/storage/file/Makefile
 src/lib-sieve/storage/dict/Makefile
 src/lib-sieve/storage/ldap/Makefile
diff --git a/src/lib-sieve/Makefile.am b/src/lib-sieve/Makefile.am
index 021aebc1ae53781844545f819a5633239602be01..938bda0a311ec86e34a933fce8cb63310241e028 100644
--- a/src/lib-sieve/Makefile.am
+++ b/src/lib-sieve/Makefile.am
@@ -48,6 +48,7 @@ endif
 
 strgdir = $(top_builddir)/src/lib-sieve/storage
 storages = \
+	$(strgdir)/data/libsieve_storage_data.la \
 	$(strgdir)/file/libsieve_storage_file.la \
 	$(strgdir)/dict/libsieve_storage_dict.la \
 	$(strgdir)/ldap/libsieve_storage_ldap.la \
diff --git a/src/lib-sieve/sieve-script-private.h b/src/lib-sieve/sieve-script-private.h
index 7f1edff72cc0c89b729cbf6082cfd9e7c2ad4c5f..3338ba45d26a413ef5ff8170757e390dce9338e5 100644
--- a/src/lib-sieve/sieve-script-private.h
+++ b/src/lib-sieve/sieve-script-private.h
@@ -78,6 +78,7 @@ void sieve_script_init
  * Built-in script drivers
  */
 
+extern const struct sieve_script sieve_data_script;
 extern const struct sieve_script sieve_file_script;
 extern const struct sieve_script sieve_dict_script;
 extern const struct sieve_script sieve_ldap_script;
diff --git a/src/lib-sieve/sieve-script.h b/src/lib-sieve/sieve-script.h
index 66198fb651a6e7ebf03a22a968f588b848dfa2cc..f3709f389eba208c1757499dc51ac64ac71de928 100644
--- a/src/lib-sieve/sieve-script.h
+++ b/src/lib-sieve/sieve-script.h
@@ -59,6 +59,14 @@ int sieve_script_check
 		const char *name, enum sieve_error *error_r)
 		ATTR_NULL(3, 4);
 
+/*
+ * Data script
+ */
+
+struct sieve_script *sieve_data_script_create_from_input
+	(struct sieve_instance *svinst, const char *name,
+		struct istream *input);
+
 /*
  * Binary
  */
diff --git a/src/lib-sieve/sieve-storage-private.h b/src/lib-sieve/sieve-storage-private.h
index 9cdb877f73d5f5ccb6cfe57426f223fb3bf4d968..97e5c9edd78feebf67e723b39c05216a07e47beb 100644
--- a/src/lib-sieve/sieve-storage-private.h
+++ b/src/lib-sieve/sieve-storage-private.h
@@ -198,6 +198,12 @@ const struct sieve_storage *sieve_storage_find_class
  * Built-in storage drivers
  */
 
+/* data (currently only for internal use) */
+
+#define SIEVE_DATA_STORAGE_DRIVER_NAME "data"
+
+extern const struct sieve_storage sieve_data_storage;
+
 /* file */
 
 #define SIEVE_FILE_STORAGE_DRIVER_NAME "file"
diff --git a/src/lib-sieve/storage/Makefile.am b/src/lib-sieve/storage/Makefile.am
index 00e770de81a1964621be4791c0d1a1307d3063b1..ba39e4a069b45fffb2b9f8a9c43c3e9a96d240b5 100644
--- a/src/lib-sieve/storage/Makefile.am
+++ b/src/lib-sieve/storage/Makefile.am
@@ -1,4 +1,5 @@
 SUBDIRS = \
+	data \
 	file \
 	dict \
 	ldap
diff --git a/src/lib-sieve/storage/data/Makefile.am b/src/lib-sieve/storage/data/Makefile.am
new file mode 100644
index 0000000000000000000000000000000000000000..c17741da4fa756c071fb04631bcf256a46fb0148
--- /dev/null
+++ b/src/lib-sieve/storage/data/Makefile.am
@@ -0,0 +1,13 @@
+noinst_LTLIBRARIES = libsieve_storage_data.la
+
+AM_CPPFLAGS = \
+	$(LIBDOVECOT_INCLUDE) \
+	-I$(top_srcdir) \
+	-I$(top_srcdir)/src/lib-sieve
+
+libsieve_storage_data_la_SOURCES = \
+	sieve-data-script.c \
+	sieve-data-storage.c
+
+noinst_HEADERS = \
+	sieve-data-storage.h
diff --git a/src/lib-sieve/storage/data/sieve-data-script.c b/src/lib-sieve/storage/data/sieve-data-script.c
new file mode 100644
index 0000000000000000000000000000000000000000..a8c8af1e726ef517513765663d3f58dbb500d643
--- /dev/null
+++ b/src/lib-sieve/storage/data/sieve-data-script.c
@@ -0,0 +1,94 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "str.h"
+#include "strfuncs.h"
+#include "istream.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+#include "sieve-dump.h"
+#include "sieve-binary.h"
+
+#include "sieve-data-storage.h"
+
+/*
+ * Script data implementation
+ */
+
+static struct sieve_data_script *sieve_data_script_alloc(void)
+{
+	struct sieve_data_script *dscript;
+	pool_t pool;
+
+	pool = pool_alloconly_create("sieve_data_script", 1024);
+	dscript = p_new(pool, struct sieve_data_script, 1);
+	dscript->script = sieve_data_script;
+	dscript->script.pool = pool;
+
+	return dscript;
+}
+
+struct sieve_script *sieve_data_script_create_from_input
+(struct sieve_instance *svinst, const char *name, struct istream *input)
+{
+	struct sieve_storage *storage;
+	struct sieve_data_script *dscript = NULL;
+
+	storage = sieve_storage_alloc(svinst, &sieve_data_storage, "", 0, FALSE);
+
+	dscript = sieve_data_script_alloc();
+	sieve_script_init(&dscript->script,
+		storage, &sieve_data_script, "data:", name);
+
+	dscript->data = input;
+	i_stream_ref(dscript->data);
+
+	sieve_storage_unref(&storage);
+
+	dscript->script.open = TRUE;
+
+	return &dscript->script;
+}
+
+static void sieve_data_script_destroy(struct sieve_script *script)
+{
+	struct sieve_data_script *dscript =
+		(struct sieve_data_script *)script;
+
+	i_stream_unref(&dscript->data);
+}
+
+static int sieve_data_script_get_stream
+(struct sieve_script *script, struct istream **stream_r,
+	enum sieve_error *error_r)
+{
+	struct sieve_data_script *dscript =
+		(struct sieve_data_script *)script;
+
+	i_stream_ref(dscript->data);
+	i_stream_seek(dscript->data, 0);
+
+	*stream_r = dscript->data;
+	*error_r = SIEVE_ERROR_NONE;
+	return 0;
+}
+
+static bool sieve_data_script_equals
+(const struct sieve_script *script ATTR_UNUSED,
+	const struct sieve_script *other ATTR_UNUSED)
+{
+	return ( script == other );
+}
+
+const struct sieve_script sieve_data_script = {
+	.driver_name = SIEVE_DATA_STORAGE_DRIVER_NAME,
+	.v = {
+		.destroy = sieve_data_script_destroy,
+
+		.get_stream = sieve_data_script_get_stream,
+
+		.equals = sieve_data_script_equals
+	}
+};
diff --git a/src/lib-sieve/storage/data/sieve-data-storage.c b/src/lib-sieve/storage/data/sieve-data-storage.c
new file mode 100644
index 0000000000000000000000000000000000000000..21b4f3511c4f68d695c96fde1444804185894094
--- /dev/null
+++ b/src/lib-sieve/storage/data/sieve-data-storage.c
@@ -0,0 +1,47 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+
+#include "sieve-common.h"
+#include "sieve-error.h"
+
+#include "sieve-data-storage.h"
+
+/*
+ * Storage class
+ */
+
+static struct sieve_storage *sieve_data_storage_alloc(void)
+{
+	struct sieve_data_storage *dstorage;
+	pool_t pool;
+
+	pool = pool_alloconly_create("sieve_data_storage", 1024);
+	dstorage = p_new(pool, struct sieve_data_storage, 1);
+	dstorage->storage = sieve_data_storage;
+	dstorage->storage.pool = pool;
+
+	return &dstorage->storage;
+}
+
+static int sieve_data_storage_init
+(struct sieve_storage *storage ATTR_UNUSED,
+	const char *const *options ATTR_UNUSED,
+	enum sieve_error *error_r ATTR_UNUSED)
+{
+	return 0;
+}
+
+/*
+ * Driver definition
+ */
+
+const struct sieve_storage sieve_data_storage = {
+	.driver_name = SIEVE_DATA_STORAGE_DRIVER_NAME,
+	.version = 0,
+	.v = {
+		.alloc = sieve_data_storage_alloc,
+		.init = sieve_data_storage_init,
+	}
+};
diff --git a/src/lib-sieve/storage/data/sieve-data-storage.h b/src/lib-sieve/storage/data/sieve-data-storage.h
new file mode 100644
index 0000000000000000000000000000000000000000..a200e2595f5179e3e2199e4e1b5df9a1a91b42bf
--- /dev/null
+++ b/src/lib-sieve/storage/data/sieve-data-storage.h
@@ -0,0 +1,30 @@
+#ifndef SIEVE_DATA_STORAGE_H
+#define SIEVE_DATA_STORAGE_H
+
+#include "sieve.h"
+#include "sieve-script-private.h"
+#include "sieve-storage-private.h"
+
+/*
+ * Storage class
+ */
+
+struct sieve_data_storage {
+	struct sieve_storage storage;
+};
+
+/*
+ * Script class
+ */
+
+struct sieve_data_script {
+	struct sieve_script script;
+
+	struct istream *data;
+};
+
+struct sieve_script *sieve_data_script_create_from_input
+	(struct sieve_instance *svinst, const char *name,
+		struct istream *input);
+
+#endif