diff --git a/README b/README
index 278c0257481acaaa64dedbae74d89ca39317401d..4578fd7d1b643e1b848f795ee5fb9ba6f1b1b26b 100644
--- a/README
+++ b/README
@@ -149,15 +149,15 @@ Extensions and their implementation status:
     encoded-character: full
 
   Other RFCs/drafts:
-    subaddress: full, but not configurable
+    subaddress: mostly full; not configurable
     comparator-i;ascii-numeric: full
     relational: full 
     copy: full
-    regex: full, but suboptimal and no UTF-8
+    regex: mostly full; but suboptimal and no UTF-8
     body: full, but text body-transform implementation is simple
-    include: almost full; needs some more work (no external binaries)
-    vacation: almost full; no support for required References header
-    imapflags: flag management works, but flags are not stored
+    include: mostly full; needs some more work (no external binaries)
+    vacation: mostly full; no support for required References header
+    imapflags: full
     variables: mostly full; currently no support for future namespaces 
 
   Low priority:
diff --git a/TODO b/TODO
index 0addc5b0736724af11422df018eebe825544f736..8e5750f3aa1f0a6252fdcc6349bcc7f5abe5ff4c 100644
--- a/TODO
+++ b/TODO
@@ -1,5 +1,4 @@
 Next (in order of descending priority/precedence):
-* Finish implementing all extensions supported by cmusieve, except notify.
 * Get rid of all <stdio.h> printf()s in the library; use trace macro instead
 * Revise extension support for comparators, match-types, address-parts and 
   side-effects. Current implementation emits redundant bytes and associated code
@@ -7,7 +6,6 @@ Next (in order of descending priority/precedence):
 * Emit line numbers for certain action commands to provide useful runtime error
   messages.
 * Improve handling of old/corrupt binaries.
-* Handle persistent side-effects for the (implicit) keep action 
 
 * Full security review. Enforce limits on number of created objects, script 
   size, execution time, etc...
diff --git a/src/lib-sieve/plugins/imapflags/ext-imapflags.c b/src/lib-sieve/plugins/imapflags/ext-imapflags.c
index 7fa2c3f6fd47cc193929c6b4cf6f3ca5a43697bc..92a4a932d54becd537e0dabff9b1532f8b77ea0f 100644
--- a/src/lib-sieve/plugins/imapflags/ext-imapflags.c
+++ b/src/lib-sieve/plugins/imapflags/ext-imapflags.c
@@ -3,8 +3,8 @@
  *
  * Authors: Stephan Bosch
  * Specification: draft-ietf-sieve-imapflags-05
- * Implementation: flag management works, not stored though. 
- * Status: under development
+ * Implementation: full 
+ * Status: experimental, largely untested
  *
  */
  
diff --git a/src/lib-sieve/plugins/imapflags/imapflags.sieve b/src/lib-sieve/plugins/imapflags/imapflags.sieve
index e33b13ebe6603738c6a6a5338e8993a02e7dbf0f..53c0fdc18e9a6eefa38e4b7bf70c6fc86a2a4220 100644
--- a/src/lib-sieve/plugins/imapflags/imapflags.sieve
+++ b/src/lib-sieve/plugins/imapflags/imapflags.sieve
@@ -25,4 +25,4 @@ if hasflag :count "ge" :comparator "i;ascii-numeric" "2" {
 	fileinto "imap-twoflags";
 }
 
-fileinto :flags "\\Seen MDNRequired \\Draft" "INBOX";
+fileinto :flags "MDNRequired \\Draft" "INBOX";
diff --git a/src/lib-sieve/plugins/imapflags/tag-flags.c b/src/lib-sieve/plugins/imapflags/tag-flags.c
index 254e15826d837e3625dde0da34cfe392d4d60d0e..5f1e6c5b85d1a7c4c32be7a979d2d790527b2ad4 100644
--- a/src/lib-sieve/plugins/imapflags/tag-flags.c
+++ b/src/lib-sieve/plugins/imapflags/tag-flags.c
@@ -235,7 +235,7 @@ static void seff_flags_print
 (const struct sieve_side_effect *seffect ATTR_UNUSED, 
 	const struct sieve_action *action ATTR_UNUSED, 
 	struct sieve_result *result,
-	void *se_context ATTR_UNUSED, bool *keep)
+	void *se_context ATTR_UNUSED, bool *keep ATTR_UNUSED)
 {
 	struct seff_flags_context *ctx = (struct seff_flags_context *) se_context;
 	unsigned int i;
@@ -243,31 +243,31 @@ static void seff_flags_print
 	if ( ctx == NULL )
 		ctx = seff_flags_get_implicit_context(result);
 	
-	printf("        + add flags:");
+	if ( ctx->flags != 0 || array_count(&ctx->keywords) ) { 
+		printf("        + add flags:");
 
-	if ( (ctx->flags & MAIL_FLAGGED) > 0 )
-		printf(" \\flagged\n");
+		if ( (ctx->flags & MAIL_FLAGGED) > 0 )
+			printf(" \\flagged\n");
 
-	if ( (ctx->flags & MAIL_ANSWERED) > 0 )
-		printf(" \\answered");
+		if ( (ctx->flags & MAIL_ANSWERED) > 0 )
+			printf(" \\answered");
 		
-	if ( (ctx->flags & MAIL_DELETED) > 0 )
-		printf(" \\deleted");
+		if ( (ctx->flags & MAIL_DELETED) > 0 )
+			printf(" \\deleted");
 					
-	if ( (ctx->flags & MAIL_SEEN) > 0 )
-		printf(" \\seen");
+		if ( (ctx->flags & MAIL_SEEN) > 0 )
+			printf(" \\seen");
 		
-	if ( (ctx->flags & MAIL_DRAFT) > 0 )
-		printf(" \\draft");
+		if ( (ctx->flags & MAIL_DRAFT) > 0 )
+			printf(" \\draft");
 
-	for ( i = 0; i < array_count(&ctx->keywords); i++ ) {
-		const char *const *keyword = array_idx(&ctx->keywords, i);
-		printf(" %s", *keyword);
-	};
+		for ( i = 0; i < array_count(&ctx->keywords); i++ ) {
+			const char *const *keyword = array_idx(&ctx->keywords, i);
+			printf(" %s", *keyword);
+		};
+	}
 	
 	printf("\n");
-
-	*keep = TRUE;
 }
 
 static bool seff_flags_pre_execute
diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c
index bfdd716687fcf119ce6cf4b4b4c221212d54a6a7..3319f0c95a046317c430d9a721245eaa0ff646b8 100644
--- a/src/lib-sieve/sieve-result.c
+++ b/src/lib-sieve/sieve-result.c
@@ -329,26 +329,71 @@ bool sieve_result_print(struct sieve_result *result)
 	return TRUE;
 }
 
-static bool sieve_result_implicit_keep(struct sieve_result *result)
+static bool sieve_result_implicit_keep
+	(struct sieve_result *result, bool rollback)
 {	
 	bool success = TRUE;
 	bool dummy = TRUE;
 	struct act_store_context ctx;
+	struct sieve_result_side_effect *rsef, *rsef_first = NULL;
 	void *tr_context;
 	
 	ctx.folder = result->action_env.scriptenv->inbox;
 	
-	/* FIXME: Handle persistent side-effects for the (implicit) keep action */
+	/* Also apply any implicit side effects if applicable */
+	if ( !rollback && result->implicit_seffects != NULL ) {
+		struct sieve_result_implicit_side_effects *implseff;
+		
+		/* Check for implicit side effects to store action */
+		implseff = (struct sieve_result_implicit_side_effects *) 
+				hash_lookup(result->implicit_seffects, &act_store);
+		
+		if ( implseff != NULL && implseff->seffects != NULL ) 
+			rsef_first = implseff->seffects->first_effect;
+		
+	}
 	
 	success = act_store.start
 		(&act_store, &result->action_env, (void *) &ctx, &tr_context);
 
+	rsef = rsef_first;
+	while ( rsef != NULL ) {
+		const struct sieve_side_effect *sef = rsef->seffect;
+		if ( sef->pre_execute != NULL ) 
+			success = success & sef->pre_execute
+				(sef, &act_store, &result->action_env, &rsef->context, tr_context);
+		rsef = rsef->next;
+	}
+
 	success = success && act_store.execute
-		(&act_store, &result->action_env, tr_context);
+			(&act_store, &result->action_env, tr_context);
+			
+	rsef = rsef_first;
+	while ( rsef != NULL ) {
+		const struct sieve_side_effect *sef = rsef->seffect;
+		if ( sef->post_execute != NULL ) 
+			success = success && sef->post_execute
+				(sef, &act_store, &result->action_env, rsef->context, tr_context);
+		rsef = rsef->next;
+	}
 	
 	if ( success ) {	
-		return act_store.commit
-			(&act_store, &result->action_env, tr_context, &dummy); 
+		success = act_store.commit
+			(&act_store, &result->action_env, tr_context, &dummy);
+
+		rsef = rsef_first;
+		while ( rsef != NULL ) {
+			const struct sieve_side_effect *sef = rsef->seffect;
+			bool keep = TRUE;
+			
+			if ( sef->post_commit != NULL ) 
+				sef->post_commit
+					(sef, &act_store, &result->action_env, rsef->context, tr_context, 
+						&keep);
+			rsef = rsef->next;
+		}
+			
+		return success; 
 	}
 		
 	act_store.rollback(&act_store, &result->action_env, tr_context, success);
@@ -494,7 +539,7 @@ int sieve_result_execute
 	if ( !commit_ok || implicit_keep ) {
 		printf("Executing implicit keep\n");
 		
-		if ( !sieve_result_implicit_keep(result) ) 
+		if ( !sieve_result_implicit_keep(result, !commit_ok) ) 
 			return -1;
 			
 		return ( commit_ok ? 1 /* Success */ : 0 /* Implicit keep executed */ );