diff --git a/src/lib-sieve/plugins/enotify/Makefile.am b/src/lib-sieve/plugins/enotify/Makefile.am
index 4d91fd8c46046a867c71ec7d1b2e1db0db3ec425..ad0818c4615e959abab0796da912edf48a85b62d 100644
--- a/src/lib-sieve/plugins/enotify/Makefile.am
+++ b/src/lib-sieve/plugins/enotify/Makefile.am
@@ -23,6 +23,7 @@ notify_methods = \
 
 libsieve_ext_enotify_la_SOURCES = \
 	ext-enotify.c \
+	ext-notify.c \
 	ext-enotify-common.c \
 	$(commands) \
 	$(tests) \
diff --git a/src/lib-sieve/plugins/enotify/cmd-notify.c b/src/lib-sieve/plugins/enotify/cmd-notify.c
index e257c3f1d148c099b0b30f4c56392cdf9ad40350..0d243b493e2b271f4b6e5b753369ac5ce1708f2f 100644
--- a/src/lib-sieve/plugins/enotify/cmd-notify.c
+++ b/src/lib-sieve/plugins/enotify/cmd-notify.c
@@ -103,16 +103,6 @@ static const struct sieve_argument notify_importance_tag = {
 	NULL, NULL 
 };
 
-/* Codes for optional arguments */
-
-enum cmd_notify_optional {
-	OPT_END,
-	OPT_FROM,
-	OPT_OPTIONS,
-	OPT_MESSAGE,
-	OPT_IMPORTANCE
-};
-
 /* 
  * Notify operation 
  */
@@ -287,13 +277,13 @@ static bool cmd_notify_registered
 (struct sieve_validator *valdtr, struct sieve_command_registration *cmd_reg) 
 {
 	sieve_validator_register_tag
-		(valdtr, cmd_reg, &notify_importance_tag, OPT_IMPORTANCE); 	
+		(valdtr, cmd_reg, &notify_importance_tag, CMD_NOTIFY_OPT_IMPORTANCE); 	
 	sieve_validator_register_tag
-		(valdtr, cmd_reg, &notify_from_tag, OPT_FROM); 	
+		(valdtr, cmd_reg, &notify_from_tag, CMD_NOTIFY_OPT_FROM); 	
 	sieve_validator_register_tag
-		(valdtr, cmd_reg, &notify_options_tag, OPT_OPTIONS); 	
+		(valdtr, cmd_reg, &notify_options_tag, CMD_NOTIFY_OPT_OPTIONS); 	
 	sieve_validator_register_tag
-		(valdtr, cmd_reg, &notify_message_tag, OPT_MESSAGE); 	
+		(valdtr, cmd_reg, &notify_message_tag, CMD_NOTIFY_OPT_MESSAGE); 	
 
 	return TRUE;
 }
@@ -379,19 +369,19 @@ static bool cmd_notify_operation_dump
 			switch ( opt_code ) {
 			case 0:
 				break;
-			case OPT_IMPORTANCE:
+			case CMD_NOTIFY_OPT_IMPORTANCE:
 				if ( !sieve_opr_number_dump(denv, address, "importance") )
 					return FALSE;
 				break;
-			case OPT_FROM:
+			case CMD_NOTIFY_OPT_FROM:
 				if ( !sieve_opr_string_dump(denv, address, "from") )
 					return FALSE;
 				break;
-			case OPT_OPTIONS:
+			case CMD_NOTIFY_OPT_OPTIONS:
 				if ( !sieve_opr_stringlist_dump(denv, address, "options") )
 					return FALSE;
 				break;
-			case OPT_MESSAGE:
+			case CMD_NOTIFY_OPT_MESSAGE:
 				if ( !sieve_opr_string_dump(denv, address, "message") )
 					return FALSE;
 				break;
@@ -446,7 +436,7 @@ static int cmd_notify_operation_execute
 			switch ( opt_code ) {
 			case 0:
 				break;
-			case OPT_IMPORTANCE:
+			case CMD_NOTIFY_OPT_IMPORTANCE:
 				if ( !sieve_opr_number_read(renv, address, &importance) ) {
 					sieve_runtime_trace_error(renv, "invalid importance operand");
 					return SIEVE_EXEC_BIN_CORRUPT;
@@ -458,19 +448,19 @@ static int cmd_notify_operation_execute
 				else if ( importance > 3 )
 					importance = 3;
 				break;
-			case OPT_FROM:
+			case CMD_NOTIFY_OPT_FROM:
 				if ( !sieve_opr_string_read(renv, address, &from) ) {
 					sieve_runtime_trace_error(renv, "invalid from operand");
 					return SIEVE_EXEC_BIN_CORRUPT;
 				}
 				break;
-			case OPT_MESSAGE:
+			case CMD_NOTIFY_OPT_MESSAGE:
 				if ( !sieve_opr_string_read(renv, address, &message) ) {
 					sieve_runtime_trace_error(renv, "invalid from operand");
 					return SIEVE_EXEC_BIN_CORRUPT;
 				}
 				break;
-			case OPT_OPTIONS:
+			case CMD_NOTIFY_OPT_OPTIONS:
 				if ( (options=sieve_opr_stringlist_read(renv, address)) == NULL ) {
 					sieve_runtime_trace_error(renv, "invalid options operand");
 					return SIEVE_EXEC_BIN_CORRUPT;
diff --git a/src/lib-sieve/plugins/enotify/ext-enotify-common.h b/src/lib-sieve/plugins/enotify/ext-enotify-common.h
index 52fad08c381fe2a5b25e1d3efe13c90c5fb6dd17..0da2e5eaca16a7480b7dcf4fcea6a19959b90ec2 100644
--- a/src/lib-sieve/plugins/enotify/ext-enotify-common.h
+++ b/src/lib-sieve/plugins/enotify/ext-enotify-common.h
@@ -13,6 +13,7 @@
  */
 
 extern const struct sieve_extension enotify_extension;
+extern const struct sieve_extension notify_extension;
 extern const struct sieve_extension_capabilities notify_capabilities;
 
 /*
@@ -21,6 +22,16 @@ extern const struct sieve_extension_capabilities notify_capabilities;
 
 extern const struct sieve_command notify_command;
 
+/* Codes for optional arguments */
+
+enum cmd_notify_optional {
+    CMD_NOTIFY_OPT_END,
+    CMD_NOTIFY_OPT_FROM,
+    CMD_NOTIFY_OPT_OPTIONS,
+    CMD_NOTIFY_OPT_MESSAGE,
+    CMD_NOTIFY_OPT_IMPORTANCE
+};
+
 /*
  * Tests
  */
diff --git a/src/lib-sieve/plugins/enotify/ext-notify.c b/src/lib-sieve/plugins/enotify/ext-notify.c
new file mode 100644
index 0000000000000000000000000000000000000000..776fae4dce42ae09cdc4fbb93993633fe8cc4b28
--- /dev/null
+++ b/src/lib-sieve/plugins/enotify/ext-notify.c
@@ -0,0 +1,374 @@
+/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file
+ */
+
+/* Extension notify
+ * ----------------
+ *
+ * Authors: Stephan Bosch
+ * Specification: draft-ietf-sieve-notify-00.txt
+ * Implementation: deprecated; provided for backwards compatibility
+ *                 denotify command is explicitly not supported.
+ * Status: deprecated
+ * 
+ */
+	
+#include <stdio.h>
+
+#include "sieve-common.h"
+
+#include "sieve-code.h"
+#include "sieve-extensions.h"
+#include "sieve-actions.h"
+#include "sieve-commands.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+#include "sieve-result.h"
+
+#include "ext-enotify-common.h"
+
+/*
+ * Commands
+ */
+
+static bool cmd_notify_registered
+	(struct sieve_validator *valdtr,
+		struct sieve_command_registration *cmd_reg);
+static bool cmd_notify_pre_validate
+	(struct sieve_validator *valdtr, struct sieve_command_context *cmd);
+static bool cmd_notify_validate
+	(struct sieve_validator *valdtr, struct sieve_command_context *cmd);
+static bool cmd_notify_generate
+	(const struct sieve_codegen_env *cgenv, 
+		struct sieve_command_context *ctx);
+
+static bool cmd_denotify_pre_validate
+	(struct sieve_validator *valdtr, struct sieve_command_context *cmd);
+
+/* Notify command
+ *
+ * Syntax:
+ *   notify [":method" string] [":id" string] 
+ *          [<":low" / ":normal" / ":high">] [":message" string]
+ */
+
+static const struct sieve_command cmd_notify = {
+	"notify",
+	SCT_COMMAND,
+	0, 0, FALSE, FALSE,
+	cmd_notify_registered,
+	cmd_notify_pre_validate,
+	cmd_notify_validate,
+	cmd_notify_generate, 
+	NULL,
+};
+
+/* Denotify command (NOT IMPLEMENTED)
+ *
+ * Syntax:
+ *   denotify [MATCH-TYPE string] [<":low" / ":normal" / ":high">]
+ */
+static const struct sieve_command cmd_denotify = {
+	"denotify",
+	SCT_COMMAND,
+	0, 0, FALSE, FALSE,
+	NULL,
+	cmd_denotify_pre_validate,
+	NULL, NULL, NULL
+};
+
+/* 
+ * Extension
+ */
+
+static bool ext_notify_load(void);
+static bool ext_notify_validator_load(struct sieve_validator *valdtr);
+
+static int ext_notify_my_id = -1;
+
+const struct sieve_extension notify_extension = { 
+	"notify", 
+	&ext_notify_my_id,
+	ext_notify_load,
+	NULL,
+	ext_notify_validator_load, 
+	NULL, NULL, NULL, NULL, NULL,
+	SIEVE_EXT_DEFINE_NO_OPERATIONS,
+	SIEVE_EXT_DEFINE_NO_OPERANDS,
+};
+
+static bool ext_notify_load(void)
+{
+	/* Make sure real extension is registered, it is needed by the binary */
+    (void)sieve_extension_require(&enotify_extension);
+
+	return TRUE;
+}
+
+/*
+ * Extension validation
+ */
+
+static bool ext_notify_validator_extension_validate
+	(struct sieve_validator *valdtr, void *context, struct sieve_ast_argument *require_arg);
+
+const struct sieve_validator_extension notify_validator_extension = {
+	&notify_extension,
+	ext_notify_validator_extension_validate,
+	NULL
+};
+
+static bool ext_notify_validator_load(struct sieve_validator *valdtr)
+{
+	/* Register validator extension to check for conflict with enotify */
+	sieve_validator_extension_register
+		(valdtr, &notify_validator_extension, NULL);
+
+	/* Register new commands */
+	sieve_validator_register_command(valdtr, &cmd_notify);
+	sieve_validator_register_command(valdtr, &cmd_denotify);
+	
+	return TRUE;
+}
+
+static bool ext_notify_validator_extension_validate
+(struct sieve_validator *valdtr, void *context ATTR_UNUSED,
+    struct sieve_ast_argument *require_arg)
+{
+	/* Check for conflict with enotify */
+	if ( sieve_validator_extension_loaded(valdtr, &enotify_extension) ) {
+		sieve_argument_validate_error(valdtr, require_arg,
+			"the (deprecated) notify extension cannot be used "
+			"together with the enotify extension");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+/*
+ * Denotify/Notify command tags
+ */
+
+/* Forward declarations */
+
+static bool cmd_notify_validate_string_tag
+	(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+		struct sieve_command_context *cmd);
+static bool cmd_notify_validate_importance_tag
+	(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+		struct sieve_command_context *cmd);
+
+/* Argument objects */
+
+static const struct sieve_argument notify_method_tag = {
+	"method",
+	NULL, NULL,
+	cmd_notify_validate_string_tag,
+	NULL, NULL
+};
+
+static const struct sieve_argument notify_id_tag = {
+	"id",
+	NULL, NULL,
+	cmd_notify_validate_string_tag,
+	NULL, NULL
+};
+
+static const struct sieve_argument notify_message_tag = {
+	"message",
+	NULL, NULL,
+	cmd_notify_validate_string_tag,
+	NULL, NULL
+};
+
+static const struct sieve_argument notify_low_tag = {
+	"low",
+	NULL, NULL,
+	cmd_notify_validate_importance_tag,
+	NULL, NULL
+};
+
+static const struct sieve_argument notify_normal_tag = {
+	"normal",
+	NULL, NULL,
+	cmd_notify_validate_importance_tag,
+	NULL, NULL
+};
+
+static const struct sieve_argument notify_high_tag = {
+	"high",
+	NULL, NULL,
+	cmd_notify_validate_importance_tag,
+	NULL, NULL
+};
+
+/*
+ * Command validation context
+ */
+
+struct cmd_notify_context_data {
+	struct sieve_ast_argument *method;
+	struct sieve_ast_argument *message;
+};
+
+/*
+ * Tag validation
+ */
+
+static bool cmd_notify_validate_string_tag
+(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
+    struct sieve_command_context *cmd)
+{
+	struct sieve_ast_argument *tag = *arg;
+	struct cmd_notify_context_data *ctx_data =
+		(struct cmd_notify_context_data *) cmd->data;
+
+	/* Detach the tag itself */
+	*arg = sieve_ast_arguments_detach(*arg, 1);
+
+    /* Check syntax:
+     *   :id <string>
+     *   :method <string>
+     *   :message <string>
+     */
+	if ( !sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, SAAT_STRING) )
+		return FALSE;
+
+	if ( tag->argument == &notify_method_tag ) {
+		ctx_data->method = *arg;
+	
+		/* Removed */
+		*arg = sieve_ast_arguments_detach(*arg, 1);
+
+	} else if ( tag->argument == &notify_id_tag ) {
+
+		/* Ignored */
+		*arg = sieve_ast_arguments_detach(*arg, 1);
+
+	} else if ( tag->argument == &notify_message_tag ) {
+		ctx_data->message = *arg;
+
+		/* Skip parameter */
+		*arg = sieve_ast_argument_next(*arg);
+	}
+
+	return TRUE;
+}
+
+static bool cmd_notify_validate_importance_tag
+(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_ast_argument **arg,
+	struct sieve_command_context *cmd ATTR_UNUSED)
+{
+	struct sieve_ast_argument *tag = *arg;
+
+	if ( tag->argument == &notify_low_tag )
+		sieve_ast_argument_number_substitute(tag, 1);
+	else if ( tag->argument == &notify_normal_tag )
+		sieve_ast_argument_number_substitute(tag, 2);
+	else
+		sieve_ast_argument_number_substitute(tag, 3);
+
+	tag->argument = &number_argument;
+
+	/* Skip parameter */
+	*arg = sieve_ast_argument_next(*arg);
+
+	return TRUE;
+}
+
+/*
+ * Command registration
+ */
+
+static bool cmd_notify_registered
+(struct sieve_validator *valdtr, struct sieve_command_registration *cmd_reg)
+{
+	sieve_validator_register_tag
+		(valdtr, cmd_reg, &notify_method_tag, 0);
+	sieve_validator_register_tag
+		(valdtr, cmd_reg, &notify_id_tag, 0);
+	sieve_validator_register_tag
+		(valdtr, cmd_reg, &notify_message_tag, CMD_NOTIFY_OPT_MESSAGE);
+
+	sieve_validator_register_tag
+		(valdtr, cmd_reg, &notify_low_tag, CMD_NOTIFY_OPT_IMPORTANCE);
+	sieve_validator_register_tag
+		(valdtr, cmd_reg, &notify_normal_tag, CMD_NOTIFY_OPT_IMPORTANCE);
+	sieve_validator_register_tag
+		(valdtr, cmd_reg, &notify_high_tag, CMD_NOTIFY_OPT_IMPORTANCE);
+
+	return TRUE;
+}
+
+/*
+ * Command validation
+ */
+
+/* Notify */
+
+static bool cmd_notify_pre_validate
+(struct sieve_validator *valdtr ATTR_UNUSED,
+	struct sieve_command_context *cmd)
+{
+	struct cmd_notify_context_data *ctx_data;
+	
+	/* Assign context */
+	ctx_data = p_new(sieve_command_pool(cmd),	
+		struct cmd_notify_context_data, 1);
+	cmd->data = ctx_data;
+
+	return TRUE;
+}
+
+static bool cmd_notify_validate
+(struct sieve_validator *valdtr, struct sieve_command_context *cmd)
+{
+	struct cmd_notify_context_data *ctx_data =
+		(struct cmd_notify_context_data *) cmd->data;
+
+	if ( ctx_data->method == NULL )	{
+		sieve_command_validate_error(valdtr, cmd,
+            "the notify command must have a ':method' argument "
+			"(the deprecated notify extension is not fully implemented)");
+        return FALSE;
+	}
+
+	if ( !sieve_ast_argument_attach(cmd->ast_node, ctx_data->method) ) {
+		/* Very unlikely */
+		sieve_command_validate_error(valdtr, cmd,
+			"generate notify command; script is too complex");
+		return FALSE;
+	}
+
+	return ext_enotify_compile_check_arguments
+		(valdtr, ctx_data->method, ctx_data->message, NULL, NULL);
+}
+
+/* Denotify */
+
+static bool cmd_denotify_pre_validate
+(struct sieve_validator *valdtr, struct sieve_command_context *cmd)
+{
+	sieve_command_validate_error(valdtr, cmd,
+		"the denotify command cannot be used "
+		"(the deprecated notify extension is not fully implemented)");
+	return FALSE;
+}
+
+/*
+ * Code generation
+ */
+
+static bool cmd_notify_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_command_context *ctx)
+{
+    sieve_operation_emit_code(cgenv->sbin, &notify_operation);
+
+    /* Emit source line */
+    sieve_code_source_line_emit(cgenv->sbin, sieve_command_source_line(ctx));
+
+    /* Generate arguments */
+    return sieve_generate_arguments(cgenv, ctx, NULL);
+}
+
diff --git a/src/lib-sieve/sieve-ast.c b/src/lib-sieve/sieve-ast.c
index bf3b991540c2ca60fd5e6965e7c35b78ae7d64c6..ce6b87b930991dac25237c3d708807680e185098 100644
--- a/src/lib-sieve/sieve-ast.c
+++ b/src/lib-sieve/sieve-ast.c
@@ -679,6 +679,12 @@ struct sieve_ast_argument *sieve_ast_arguments_detach
 	return sieve_ast_arg_list_detach(first, count);
 }
 
+bool sieve_ast_argument_attach
+(struct sieve_ast_node *node, struct sieve_ast_argument *argument)
+{
+	return sieve_ast_node_add_argument(node, argument);
+}
+
 const char *sieve_ast_argument_type_name
 (enum sieve_ast_argument_type arg_type) 
 {
diff --git a/src/lib-sieve/sieve-ast.h b/src/lib-sieve/sieve-ast.h
index 77567a2410206dbed1dd2634c29b03e18a12113c..8682a900def9db283deb259e1f0ce0da2de76d73 100644
--- a/src/lib-sieve/sieve-ast.h
+++ b/src/lib-sieve/sieve-ast.h
@@ -266,6 +266,8 @@ struct sieve_ast_argument *sieve_ast_argument_stringlist_substitute
 
 struct sieve_ast_argument *sieve_ast_arguments_detach
 	(struct sieve_ast_argument *first, unsigned int count);
+bool sieve_ast_argument_attach
+	(struct sieve_ast_node *node, struct sieve_ast_argument *argument);
 	
 const char *sieve_ast_argument_type_name(enum sieve_ast_argument_type arg_type);
 #define sieve_ast_argument_name(argument) \
diff --git a/src/lib-sieve/sieve-extensions.c b/src/lib-sieve/sieve-extensions.c
index cd737e916cdf17b93d744750311a15ec25923e56..bb3cfffc52068470f04a244b143f218e6a141020 100644
--- a/src/lib-sieve/sieve-extensions.c
+++ b/src/lib-sieve/sieve-extensions.c
@@ -120,10 +120,12 @@ const unsigned int sieve_core_extensions_count =
  */
 
 extern const struct sieve_extension imapflags_extension;
+extern const struct sieve_extension notify_extension;
 
 const struct sieve_extension *sieve_deprecated_extensions[] = {
 	/* Deprecated extensions */
-	&imapflags_extension
+	&imapflags_extension,
+	&notify_extension
 };
 
 const unsigned int sieve_deprecated_extensions_count =