diff --git a/src/lib-sieve/cmd-redirect.c b/src/lib-sieve/cmd-redirect.c
index 6d1f23e00d151320782c14491bcde7a073f38afb..3b1a85091e0e2b4edc708bb35380bc0ef7fe0198 100644
--- a/src/lib-sieve/cmd-redirect.c
+++ b/src/lib-sieve/cmd-redirect.c
@@ -321,7 +321,7 @@ static int act_redirect_send
 	struct istream *input;
 	struct ostream *output;
 	const char *error;
-	void *smtp_handle;
+	struct sieve_smtp_context *sctx;
 	int ret;
 
 	/* Just to be sure */
@@ -335,7 +335,7 @@ static int act_redirect_send
 		return SIEVE_EXEC_TEMP_FAILURE;
 
 	/* Open SMTP transport */
-	smtp_handle = sieve_smtp_open(senv, ctx->to_address, sender, &output);
+	sctx = sieve_smtp_start_single(senv, ctx->to_address, sender, &output);
 
 	/* Remove unwanted headers */
 	input = i_stream_create_header_filter
@@ -358,7 +358,7 @@ static int act_redirect_send
   i_stream_unref(&input);
 
 	/* Close SMTP transport */
-	if ( (ret=sieve_smtp_close(senv, smtp_handle, &error)) <= 0 ) {
+	if ( (ret=sieve_smtp_finish(sctx, &error)) <= 0 ) {
 		if ( ret < 0 ) {
 			sieve_result_global_log_error(aenv,
 				"failed to redirect message to <%s>: %s "
diff --git a/src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c b/src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
index e9490f0e449f05b450ccd8adedc65e65dd3a176b..1272ee7e35b981f057feacf586edb9e346915319 100644
--- a/src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+++ b/src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
@@ -385,10 +385,10 @@ static bool ntfy_mailto_send
 	const char *from = NULL, *from_smtp = NULL;
 	const char *subject = mtctx->uri->subject;
 	const char *body = mtctx->uri->body;
-	string_t *to, *cc;
+	string_t *to, *cc, *all;
 	const struct uri_mailto_recipient *recipients;
 	const struct uri_mailto_header_field *headers;
-	void *smtp_handle;
+	struct sieve_smtp_context *sctx;
 	struct ostream *output;
 	string_t *msg;
 	unsigned int count, i, hcount, h;
@@ -445,6 +445,7 @@ static bool ntfy_mailto_send
 	/* Compose To and Cc headers */
 	to = NULL;
 	cc = NULL;
+	all = t_str_new(256);
 	for ( i = 0; i < count; i++ ) {
 		if ( recipients[i].carbon_copy ) {
 			if ( cc == NULL ) {
@@ -463,6 +464,15 @@ static bool ntfy_mailto_send
 				str_append(to, recipients[i].full);
 			}
 		}
+		if ( i < 3) {
+			if ( i > 0 )
+				str_append(all, ", ");
+			str_append_c(all, '<');
+			str_append(all, str_sanitize(recipients[i].normalized, 256));
+			str_append_c(all, '>');
+		} else if (i == 3) {
+			str_printfa(all, ", ... (%u total)", count);
+		}
 	}
 
 	msg = t_str_new(512);
@@ -534,30 +544,28 @@ static bool ntfy_mailto_send
 		str_append(msg, "\r\nNotification of new message.\r\n");
 	}
 
+	sctx = sieve_smtp_start(senv, from_smtp);
+
 	/* Send message to all recipients */
-	for ( i = 0; i < count; i++ ) {
-		smtp_handle = sieve_smtp_open
-			(senv, recipients[i].normalized, from_smtp, &output);
+	for ( i = 0; i < count; i++ )
+		sieve_smtp_add_rcpt(sctx, recipients[i].normalized);
 
-		o_stream_send(output, str_data(msg), str_len(msg));
+	output = sieve_smtp_send(sctx);
+	o_stream_send(output, str_data(msg), str_len(msg));
 
-		if ( (ret=sieve_smtp_close(senv, smtp_handle, &error)) <= 0 ) {
-			if (ret < 0)  {
-				sieve_enotify_global_log_error(nenv,
-					"failed to send mail notification to <%s>: %s (temporary failure)",
-					str_sanitize(recipients[i].normalized, 256),
-					str_sanitize(error, 512));
-			} else {
-				sieve_enotify_global_error(nenv,
-					"failed to send mail notification to <%s>: %s (permanent failure)",
-					str_sanitize(recipients[i].normalized, 256),
-					str_sanitize(error, 512));
-			}
+	if ( (ret=sieve_smtp_finish(sctx, &error)) <= 0 ) {
+		if (ret < 0)  {
+			sieve_enotify_global_log_error(nenv,
+				"failed to send mail notification to %s: %s (temporary failure)",
+				str_c(all),	str_sanitize(error, 512));
 		} else {
-			sieve_enotify_global_info(nenv,
-				"sent mail notification to <%s>",
-				str_sanitize(recipients[i].normalized, 256));
+			sieve_enotify_global_error(nenv,
+				"failed to send mail notification to %s: %s (permanent failure)",
+				str_c(all),	str_sanitize(error, 512));
 		}
+	} else {
+		sieve_enotify_global_info(nenv,
+			"sent mail notification to %s", str_c(all));
 	}
 
 	return TRUE;
diff --git a/src/lib-sieve/plugins/notify/cmd-notify.c b/src/lib-sieve/plugins/notify/cmd-notify.c
index ffdb3b5b78b015760903200ab021dacfb2af17b4..090dea8a2f367ccd124f40bd67fd196cea7dc31b 100644
--- a/src/lib-sieve/plugins/notify/cmd-notify.c
+++ b/src/lib-sieve/plugins/notify/cmd-notify.c
@@ -689,12 +689,11 @@ static bool act_notify_send
 {
 	const struct sieve_script_env *senv = aenv->scriptenv;
 	const struct ext_notify_recipient *recipients;
-	void *smtp_handle;
+	struct sieve_smtp_context *sctx;
 	unsigned int count, i;
 	struct ostream *output;
-	string_t *msg;
+	string_t *msg, *to, *all;
 	const char *outmsgid, *error;
-	size_t hdr_size;
 	int ret;
 
 	/* Get recipients */
@@ -706,7 +705,7 @@ static bool act_notify_send
 	}
 
 	/* Just to be sure */
-	if ( senv->smtp_open == NULL || senv->smtp_close == NULL ) {
+	if ( !sieve_smtp_available(senv) ) {
 		sieve_result_global_warning(aenv,
 			"notify action has no means to send mail");
 		return TRUE;
@@ -753,45 +752,54 @@ static bool act_notify_send
 		rfc2822_header_write(msg, "Content-Transfer-Encoding", "7bit");
 	}
 
-	hdr_size = str_len(msg);
+	outmsgid = sieve_message_get_new_id(aenv->svinst);
+	rfc2822_header_write(msg, "Message-ID", outmsgid);
 
-	/* Send message to all recipients */
+	if ( sieve_message_get_sender(aenv->msgctx) != NULL )
+		sctx = sieve_smtp_start(senv, senv->postmaster_address);
+	else
+		sctx = sieve_smtp_start(senv, NULL);
+
+	/* Add all recipients (and compose To header field) */
+	to = t_str_new(128);
+	all = t_str_new(256);
 	for ( i = 0; i < count; i++ ) {
-		if ( sieve_message_get_sender(aenv->msgctx) != NULL )
-			smtp_handle = sieve_smtp_open
-				(senv, recipients[i].normalized, senv->postmaster_address, &output);
-		else
-			smtp_handle = sieve_smtp_open
-				(senv, recipients[i].normalized, NULL, &output);
-
-		str_truncate(msg, hdr_size);
-
-		outmsgid = sieve_message_get_new_id(aenv->svinst);
-		rfc2822_header_write(msg, "Message-ID", outmsgid);
-		rfc2822_header_write(msg, "To", recipients[i].full);
-
-		/* Generate message body */
-		str_printfa(msg, "\r\n%s\r\n", act->message);
-
-		o_stream_send(output, str_data(msg), str_len(msg));
-
-		if ( (ret=sieve_smtp_close(senv, smtp_handle, &error)) <= 0 ) {
-			if (ret < 0) {
-				sieve_result_global_log_error(aenv,
-					"failed to send mail notification to <%s>: %s (temporary failure)",
-					str_sanitize(recipients[i].normalized, 256),
-					str_sanitize(error, 512));
-			} else {
-				sieve_result_global_error(aenv,
-					"failed to send mail notification to <%s>: %s (permanent failure)",
-					str_sanitize(recipients[i].normalized, 256),
-					str_sanitize(error, 512));
-			}
+		sieve_smtp_add_rcpt(sctx, recipients[i].normalized);
+		if ( i > 0 )
+			str_append(to, ", ");
+		str_append(to, recipients[i].full);
+		if ( i < 3) {
+			if ( i > 0 )
+				str_append(all, ", ");
+			str_append_c(all, '<');
+			str_append(all, str_sanitize(recipients[i].normalized, 256));
+			str_append_c(all, '>');
+		} else if (i == 3) {
+			str_printfa(all, ", ... (%u total)", count);
+		}
+	}
+
+	rfc2822_header_write(msg, "To", str_c(to));
+
+	/* Generate message body */
+	str_printfa(msg, "\r\n%s\r\n", act->message);
+
+	output = sieve_smtp_send(sctx);
+	o_stream_send(output, str_data(msg), str_len(msg));
+
+	if ( (ret=sieve_smtp_finish(sctx, &error)) <= 0 ) {
+		if (ret < 0) {
+			sieve_result_global_log_error(aenv,
+				"failed to send mail notification to %s: %s (temporary failure)",
+				str_c(all),	str_sanitize(error, 512));
 		} else {
-			sieve_result_global_log(aenv,
-				"sent mail notification to <%s>",
-				str_sanitize(recipients[i].normalized, 256));
+			sieve_result_global_error(aenv,
+				"failed to send mail notification to %s: %s (permanent failure)",
+				str_c(all),	str_sanitize(error, 512));
 		}
+	} else {
+		sieve_result_global_log(aenv,
+			"sent mail notification to %s", str_c(all));
 	}
 
 	return TRUE;
diff --git a/src/lib-sieve/plugins/vacation/cmd-vacation.c b/src/lib-sieve/plugins/vacation/cmd-vacation.c
index 64a2ca72c42b00acc126c1ed7e8cd9369dce324f..3a36859bbe20d3ed3c419392f7207180136d0c36 100644
--- a/src/lib-sieve/plugins/vacation/cmd-vacation.c
+++ b/src/lib-sieve/plugins/vacation/cmd-vacation.c
@@ -901,7 +901,7 @@ static bool act_vacation_send
 {
 	const struct sieve_message_data *msgdata = aenv->msgdata;
 	const struct sieve_script_env *senv = aenv->scriptenv;
-	void *smtp_handle;
+	struct sieve_smtp_context *sctx;
 	struct ostream *output;
 	string_t *msg;
  	const char *const *headers;
@@ -933,7 +933,8 @@ static bool act_vacation_send
 
 	/* Open smtp session */
 
-	smtp_handle = sieve_smtp_open(senv, reply_to, smtp_from, &output);
+	sctx = sieve_smtp_start_single(senv, reply_to, smtp_from, &output);
+
 	outmsgid = sieve_message_get_new_id(aenv->svinst);
 
 	/* Produce a proper reply */
@@ -992,7 +993,7 @@ static bool act_vacation_send
   o_stream_send(output, str_data(msg), str_len(msg));
 
 	/* Close smtp session */
-	if ( (ret=sieve_smtp_close(senv, smtp_handle, &error)) <= 0 ) {
+	if ( (ret=sieve_smtp_finish(sctx, &error)) <= 0 ) {
 		if ( ret < 0 ) {
 			sieve_result_global_log_error(aenv,
 				"failed to send vacation response to <%s>: %s (temporary error)",
diff --git a/src/lib-sieve/sieve-actions.c b/src/lib-sieve/sieve-actions.c
index 4bcf4a8416f76957753398b6d95bc52804e34d6c..9e39fac426c08a28341d489c089a144f7aa264ed 100644
--- a/src/lib-sieve/sieve-actions.c
+++ b/src/lib-sieve/sieve-actions.c
@@ -783,20 +783,20 @@ static bool sieve_action_do_reject_mail
 	const struct sieve_message_data *msgdata = aenv->msgdata;
 	struct istream *input;
 	struct ostream *output;
-	void *smtp_handle;
+	struct sieve_smtp_context *sctx;
 	const char *new_msgid, *boundary, *header, *error;
   string_t *hdr;
 	int ret;
 
+	sctx = sieve_smtp_start_single(senv, sender, NULL, &output);
+
 	/* Just to be sure */
-	if ( !sieve_smtp_available(senv) ) {
+	if ( sctx == NULL ) {
 		sieve_result_global_warning
 			(aenv, "reject action has no means to send mail");
 		return TRUE;
 	}
 
-	smtp_handle = sieve_smtp_open(senv, sender, NULL, &output);
-
 	new_msgid = sieve_message_get_new_id(svinst);
 	boundary = t_strdup_printf("%s/%s", my_pid, svinst->hostname);
 
@@ -874,7 +874,7 @@ static bool sieve_action_do_reject_mail
   str_printfa(hdr, "\r\n\r\n--%s--\r\n", boundary);
   o_stream_send(output, str_data(hdr), str_len(hdr));
 
-	if ( (ret=sieve_smtp_close(senv, smtp_handle, &error)) <= 0 ) {
+	if ( (ret=sieve_smtp_finish(sctx, &error)) <= 0 ) {
 		if ( ret < 0 ) {
 			sieve_result_global_log_error(aenv,
 				"failed to send rejection message to <%s>: %s "
@@ -885,7 +885,6 @@ static bool sieve_action_do_reject_mail
 				"failed to send rejection message to <%s>: %s "
 				"(permanent failure)",
 				str_sanitize(sender, 256), str_sanitize(error, 512));
-
 		}
 		return FALSE;
 	}
diff --git a/src/lib-sieve/sieve-smtp.c b/src/lib-sieve/sieve-smtp.c
index 3ffdcb6c939eab403362beeb412e1d97694b87f0..335a8abdc5f7d50b260ce42d3fe295b7e84cc35f 100644
--- a/src/lib-sieve/sieve-smtp.c
+++ b/src/lib-sieve/sieve-smtp.c
@@ -5,28 +5,75 @@
 #include "sieve-common.h"
 #include "sieve-smtp.h"
 
+struct sieve_smtp_context {
+	const struct sieve_script_env *senv;
+	void *handle;
+	
+	unsigned int sent:1;
+};
+
 bool sieve_smtp_available
 (const struct sieve_script_env *senv)
 {
-	return ( senv->smtp_open != NULL && senv->smtp_close != NULL );
+	return ( senv->smtp_start != NULL && senv->smtp_add_rcpt != NULL &&
+		senv->smtp_send != NULL && senv->smtp_finish != NULL );
 }
 
-void *sieve_smtp_open
-(const struct sieve_script_env *senv, const char *destination,
-    const char *return_path, struct ostream **output_r)
+struct sieve_smtp_context *sieve_smtp_start
+(const struct sieve_script_env *senv, const char *return_path)
 {
+	struct sieve_smtp_context *sctx;
+	void *handle;
+
 	if ( !sieve_smtp_available(senv) )
 		return NULL;
 
-	return senv->smtp_open(senv, destination, return_path, output_r);
+	handle = senv->smtp_start(senv, return_path);
+	i_assert( handle != NULL );
+	
+	sctx = i_new(struct sieve_smtp_context, 1);
+	sctx->senv = senv;
+	sctx->handle = handle;
+
+	return sctx;
+}
+
+void sieve_smtp_add_rcpt
+(struct sieve_smtp_context *sctx, const char *address)
+{
+	i_assert(!sctx->sent);
+	sctx->senv->smtp_add_rcpt(sctx->handle, address);
+}
+
+struct ostream *sieve_smtp_send
+(struct sieve_smtp_context *sctx)
+{
+	i_assert(!sctx->sent);
+	sctx->sent = TRUE;
+
+	return sctx->senv->smtp_send(sctx->handle);
+}
+
+struct sieve_smtp_context *sieve_smtp_start_single
+(const struct sieve_script_env *senv, const char *destination,
+ 	const char *return_path, struct ostream **output_r)
+{
+	struct sieve_smtp_context *sctx;
+
+	sctx = sieve_smtp_start(senv, return_path);
+	sieve_smtp_add_rcpt(sctx, destination);
+	*output_r = sieve_smtp_send(sctx);
+
+	return sctx;
 }
 
-int sieve_smtp_close
-(const struct sieve_script_env *senv, void *handle,
-	const char **error_r)
+int sieve_smtp_finish
+(struct sieve_smtp_context *sctx, const char **error_r)
 {
-	i_assert( sieve_smtp_available(senv) );
+	const struct sieve_script_env *senv = sctx->senv;
+	void *handle = sctx->handle;
 
-	return senv->smtp_close(senv, handle, error_r);
+	i_free(sctx);
+	return senv->smtp_finish(handle, error_r);
 }
 
diff --git a/src/lib-sieve/sieve-smtp.h b/src/lib-sieve/sieve-smtp.h
index fa68bb239b6d99a6649e6c16bbdf165029015a5f..d8684ead7dd37a35d377fac8c14853c7958140df 100644
--- a/src/lib-sieve/sieve-smtp.h
+++ b/src/lib-sieve/sieve-smtp.h
@@ -9,12 +9,20 @@
 bool sieve_smtp_available
 	(const struct sieve_script_env *senv);
 
-// FIXME: support multiple recipients
-void *sieve_smtp_open
+struct sieve_smtp_context;
+
+struct sieve_smtp_context *sieve_smtp_start
+	(const struct sieve_script_env *senv, const char *return_path);
+void sieve_smtp_add_rcpt
+	(struct sieve_smtp_context *sctx, const char *address);
+struct ostream *sieve_smtp_send
+	(struct sieve_smtp_context *sctx);
+
+struct sieve_smtp_context *sieve_smtp_start_single
 	(const struct sieve_script_env *senv, const char *destination,
-   	const char *return_path, struct ostream **output_r);
-int sieve_smtp_close
-	(const struct sieve_script_env *senv, void *handle,
-		const char **error_r);
+ 		const char *return_path, struct ostream **output_r);
+
+int sieve_smtp_finish
+	(struct sieve_smtp_context *sctx, const char **error_r);
 
 #endif /* __SIEVE_SMTP_H */
diff --git a/src/lib-sieve/sieve-types.h b/src/lib-sieve/sieve-types.h
index ed902313990b2b139f182dffb3a480c57aefd072..bd9de2187f2a6bd93d23a1a52e44822e3bfec48b 100644
--- a/src/lib-sieve/sieve-types.h
+++ b/src/lib-sieve/sieve-types.h
@@ -192,13 +192,15 @@ struct sieve_script_env {
 	/* Callbacks */
 
 	/* Interface for sending mail */
-	void *(*smtp_open)
-		(const struct sieve_script_env *senv, const char *destination,
-			const char *return_path, struct ostream **output_r);
+	void *(*smtp_start)
+		(const struct sieve_script_env *senv, const char *return_path);
+	/* Add a new recipient */
+	void (*smtp_add_rcpt)	(void *handle, const char *address);
+	/* Get an output stream where the message can be written to. The recipients
+	   must already be added before calling this. */
+	struct ostream *(*smtp_send)(void *handle);
 	/* Returns 1 on success, 0 on permanent failure, -1 on temporary failure. */
-	int (*smtp_close)
-		(const struct sieve_script_env *senv, void *handle,
-			const char **error_r);
+	int (*smtp_finish)(void *handle, const char **error_r);
 
 	/* Interface for marking and checking duplicates */
 	int (*duplicate_check)
diff --git a/src/plugins/lda-sieve/lda-sieve-plugin.c b/src/plugins/lda-sieve/lda-sieve-plugin.c
index a426c961fa470501667e7276db51d86f17204a7f..b48edb0fdc3fbe0d052f7b6c86913954bb70649f 100644
--- a/src/plugins/lda-sieve/lda-sieve-plugin.c
+++ b/src/plugins/lda-sieve/lda-sieve-plugin.c
@@ -68,20 +68,31 @@ static const struct sieve_callbacks lda_sieve_callbacks = {
  * Mail transmission
  */
 
-static void *lda_sieve_smtp_open
-(const struct sieve_script_env *senv, const char *destination,
-	const char *return_path, struct ostream **output_r)
+static void *lda_sieve_smtp_start
+(const struct sieve_script_env *senv, const char *return_path)
 {
 	struct mail_deliver_context *dctx =
 		(struct mail_deliver_context *) senv->script_context;
 
-	return (void *)smtp_client_init
-		(dctx->set, destination, return_path, output_r);
+	return (void *)smtp_client_init(dctx->set, return_path);
 }
 
-static int lda_sieve_smtp_close
-(const struct sieve_script_env *senv ATTR_UNUSED, void *handle,
-	const char **error_r)
+static void lda_sieve_smtp_add_rcpt(void *handle, const char *address)
+{
+	struct smtp_client *smtp_client = (struct smtp_client *) handle;
+
+	smtp_client_add_rcpt(smtp_client, address);
+}
+
+static struct ostream *lda_sieve_smtp_send(void *handle)
+{
+	struct smtp_client *smtp_client = (struct smtp_client *) handle;
+
+	return smtp_client_send(smtp_client);
+}
+
+static int lda_sieve_smtp_finish
+(void *handle, const char **error_r)
 {
 	struct smtp_client *smtp_client = (struct smtp_client *) handle;
 
@@ -864,8 +875,10 @@ static int lda_sieve_execute
 		scriptenv.mailbox_autosubscribe = mdctx->set->lda_mailbox_autosubscribe;
 		scriptenv.user = mdctx->dest_user;
 		scriptenv.postmaster_address = mdctx->set->postmaster_address;
-		scriptenv.smtp_open = lda_sieve_smtp_open;
-		scriptenv.smtp_close = lda_sieve_smtp_close;
+		scriptenv.smtp_start = lda_sieve_smtp_start;
+		scriptenv.smtp_add_rcpt = lda_sieve_smtp_add_rcpt;
+		scriptenv.smtp_send = lda_sieve_smtp_send;
+		scriptenv.smtp_finish = lda_sieve_smtp_finish;
 		scriptenv.duplicate_mark = lda_sieve_duplicate_mark;
 		scriptenv.duplicate_check = lda_sieve_duplicate_check;
 		scriptenv.reject_mail = lda_sieve_reject_mail;
diff --git a/src/sieve-tools/sieve-filter.c b/src/sieve-tools/sieve-filter.c
index 466277543d4db0cccaaa030e80f0423f0fdbfec6..b5e420600ba8235139ea30a9b05faf8dab67d757 100644
--- a/src/sieve-tools/sieve-filter.c
+++ b/src/sieve-tools/sieve-filter.c
@@ -534,8 +534,6 @@ int main(int argc, char **argv)
 	scriptenv.default_mailbox = dst_mailbox;
 	scriptenv.user = mail_user;
 	scriptenv.postmaster_address = "postmaster@example.com";
-	scriptenv.smtp_open = NULL;
-	scriptenv.smtp_close = NULL;
 
 	/* Compose filter context */
 	memset(&sfdata, 0, sizeof(sfdata));
diff --git a/src/sieve-tools/sieve-test.c b/src/sieve-tools/sieve-test.c
index 59ec4d70997afeabcf85f6b1c1f135309756eb17..3de246aeb202da1e13f057f39a3739c7c0051b94 100644
--- a/src/sieve-tools/sieve-test.c
+++ b/src/sieve-tools/sieve-test.c
@@ -56,22 +56,34 @@ static void print_help(void)
  * Dummy SMTP session
  */
 
-static void *sieve_smtp_open
-(const struct sieve_script_env *senv ATTR_UNUSED, const char *destination,
-	const char *return_path, struct ostream **output_r)
+static void *sieve_smtp_start
+(const struct sieve_script_env *senv ATTR_UNUSED,
+	const char *return_path)
 {
-	i_info("sending message from <%s> to <%s>:",
-		( return_path == NULL ? "" : return_path ), destination);
-	printf("\nSTART MESSAGE:\n");
+	struct ostream *output;
 
-	*output_r = o_stream_create_fd(STDOUT_FILENO, (size_t)-1, FALSE);
+	i_info("sending message from <%s>:",
+		( return_path == NULL ? "" : return_path ));
 
-	return (void*)*output_r;
+	output = o_stream_create_fd(STDOUT_FILENO, (size_t)-1, FALSE);
+	return (void*)output;
 }
 
-static int sieve_smtp_close
-(const struct sieve_script_env *senv ATTR_UNUSED, void *handle,
-	const char **error_r ATTR_UNUSED)
+static void sieve_smtp_add_rcpt
+(void *handle ATTR_UNUSED, const char *address)
+{
+	printf("\nRECIPIENT: %s\n", address);
+}
+
+static struct ostream *sieve_smtp_send(void *handle)
+{
+	printf("START MESSAGE:\n");
+
+	return (struct ostream *)handle;
+}
+
+static int sieve_smtp_finish
+(void *handle, const char **error_r ATTR_UNUSED)
 {
 	struct ostream *output = (struct ostream *)handle;
 
@@ -273,8 +285,10 @@ int main(int argc, char **argv)
 		scriptenv.default_mailbox = mailbox;
 		scriptenv.user = sieve_tool_get_mail_user(sieve_tool);
 		scriptenv.postmaster_address = "postmaster@example.com";
-		scriptenv.smtp_open = sieve_smtp_open;
-		scriptenv.smtp_close = sieve_smtp_close;
+		scriptenv.smtp_start = sieve_smtp_start;
+		scriptenv.smtp_add_rcpt = sieve_smtp_add_rcpt;
+		scriptenv.smtp_send = sieve_smtp_send;
+		scriptenv.smtp_finish = sieve_smtp_finish;
 		scriptenv.duplicate_mark = duplicate_mark;
 		scriptenv.duplicate_check = duplicate_check;
 		scriptenv.trace_stream = tracestream;
diff --git a/src/testsuite/testsuite-script.c b/src/testsuite/testsuite-script.c
index 7a842241ab06a0e3768585fac1ea48ace4fccbf3..b3d24fcc55ec7ebbe00eb6bb7e8112fd9c943cd5 100644
--- a/src/testsuite/testsuite-script.c
+++ b/src/testsuite/testsuite-script.c
@@ -110,8 +110,10 @@ bool testsuite_script_run(const struct sieve_runtime_env *renv)
 	memset(&scriptenv, 0, sizeof(scriptenv));
 	scriptenv.default_mailbox = "INBOX";
 	scriptenv.postmaster_address = "postmaster@example.com";
-	scriptenv.smtp_open = NULL;
-	scriptenv.smtp_close = NULL;
+	scriptenv.smtp_start = NULL;
+	scriptenv.smtp_add_rcpt = NULL;
+	scriptenv.smtp_send = NULL;
+	scriptenv.smtp_finish = NULL;
 	scriptenv.duplicate_mark = NULL;
 	scriptenv.duplicate_check = NULL;
 	scriptenv.user = renv->scriptenv->user;
@@ -181,8 +183,10 @@ bool testsuite_script_multiscript
 	memset(&scriptenv, 0, sizeof(scriptenv));
 	scriptenv.default_mailbox = "INBOX";
 	scriptenv.postmaster_address = "postmaster@example.com";
-	scriptenv.smtp_open = NULL;
-	scriptenv.smtp_close = NULL;
+	scriptenv.smtp_start = NULL;
+	scriptenv.smtp_add_rcpt = NULL;
+	scriptenv.smtp_send = NULL;
+	scriptenv.smtp_finish = NULL;
 	scriptenv.duplicate_mark = NULL;
 	scriptenv.duplicate_check = NULL;
 	scriptenv.user = renv->scriptenv->user;
diff --git a/src/testsuite/testsuite-smtp.c b/src/testsuite/testsuite-smtp.c
index fc9878d261c7e23f1caec6ec014ebf93c5c7a195..d2944fa95347522b2750c5eb6fc8c0dd1bef4113 100644
--- a/src/testsuite/testsuite-smtp.c
+++ b/src/testsuite/testsuite-smtp.c
@@ -68,48 +68,66 @@ void testsuite_smtp_reset(void)
  */
 
 struct testsuite_smtp {
-	const char *tmp_path;
+	char *msg_file, *return_path;
 	struct ostream *output;
 };
 
-void *testsuite_smtp_open
-(const struct sieve_script_env *senv ATTR_UNUSED, const char *destination,
-	const char *return_path, struct ostream **output_r)
+void testsuite_smtp_add_rcpt(void *handle, const char *address);
+struct ostream *testsuite_smtp_send(void *handle);
+int testsuite_smtp_finish
+	(void *handle, const char **error_r);
+
+
+void *testsuite_smtp_start
+(const struct sieve_script_env *senv ATTR_UNUSED, const char *return_path)
 {
-	struct testsuite_smtp_message smtp_msg;
 	struct testsuite_smtp *smtp;
 	unsigned int smtp_count = array_count(&testsuite_smtp_messages);
 	int fd;
 
-	smtp_msg.file = p_strdup_printf(testsuite_smtp_pool,
-		"%s/%d.eml", testsuite_smtp_tmp, smtp_count);
-	smtp_msg.envelope_from =
-		( return_path != NULL ? p_strdup(testsuite_smtp_pool, return_path) : NULL );
-	smtp_msg.envelope_to = p_strdup(testsuite_smtp_pool, destination);
-
-	array_append(&testsuite_smtp_messages, &smtp_msg, 1);
-
-	smtp = t_new(struct testsuite_smtp, 1);
-	smtp->tmp_path = smtp_msg.file;
+	smtp = i_new(struct testsuite_smtp, 1);
 
-	if ( (fd=open(smtp->tmp_path, O_WRONLY | O_CREAT, 0600)) < 0 ) {
+	smtp->msg_file = i_strdup_printf("%s/%d.eml", testsuite_smtp_tmp, smtp_count);
+	smtp->return_path = i_strdup(return_path);
+	
+	if ( (fd=open(smtp->msg_file, O_WRONLY | O_CREAT, 0600)) < 0 ) {
 		i_fatal("failed create tmp file for SMTP simulation: open(%s) failed: %m",
-			smtp->tmp_path);
+			smtp->msg_file);
 	}
 
 	smtp->output = o_stream_create_fd(fd, (size_t)-1, TRUE);
-	*output_r = smtp->output;
 
 	return (void *) smtp;
 }
 
-int testsuite_smtp_close
-(const struct sieve_script_env *senv ATTR_UNUSED, void *handle,
-	const char **error_r ATTR_UNUSED)
+void testsuite_smtp_add_rcpt(void *handle, const char *address)
+{
+	struct testsuite_smtp *smtp = (struct testsuite_smtp *) handle;
+	struct testsuite_smtp_message *msg;
+
+	msg = array_append_space(&testsuite_smtp_messages);
+
+	msg->file = p_strdup(testsuite_smtp_pool, smtp->msg_file);
+	msg->envelope_from = p_strdup(testsuite_smtp_pool, smtp->return_path);
+	msg->envelope_to = p_strdup(testsuite_smtp_pool, address);
+}
+
+struct ostream *testsuite_smtp_send(void *handle)
+{
+	struct testsuite_smtp *smtp = (struct testsuite_smtp *) handle;
+
+	return smtp->output;
+}
+
+int testsuite_smtp_finish
+(void *handle,	const char **error_r ATTR_UNUSED)
 {
 	struct testsuite_smtp *smtp = (struct testsuite_smtp *) handle;
 
 	o_stream_unref(&smtp->output);
+	i_free(smtp->msg_file);
+	i_free(smtp->return_path);
+	i_free(smtp);
 	return 1;
 }
 
diff --git a/src/testsuite/testsuite-smtp.h b/src/testsuite/testsuite-smtp.h
index 249f1a8d3ec60c46eefb34b66d54c008c10aeb10..3a028f466bbb5e8723512b127c19062336834953 100644
--- a/src/testsuite/testsuite-smtp.h
+++ b/src/testsuite/testsuite-smtp.h
@@ -12,11 +12,13 @@ void testsuite_smtp_reset(void);
  * Simulated SMTP out
  */
 
-void *testsuite_smtp_open
-	(const struct sieve_script_env *senv ATTR_UNUSED, const char *destination,
-		const char *return_path, struct ostream **output_r);
-int testsuite_smtp_close
-	(const struct sieve_script_env *senv, void *handle, const char **error_r);
+void *testsuite_smtp_start
+	(const struct sieve_script_env *senv ATTR_UNUSED,
+		const char *return_path);
+void testsuite_smtp_add_rcpt(void *handle, const char *address);
+struct ostream *testsuite_smtp_send(void *handle);
+int testsuite_smtp_finish
+	(void *handle, const char **error_r);
 
 /*
  * Access
diff --git a/src/testsuite/testsuite.c b/src/testsuite/testsuite.c
index 11b3a5c0520d421f1ab6ef1c10cb577fe07f8852..d53eafbc80786476a2a27876545aec1cc6d9dddc 100644
--- a/src/testsuite/testsuite.c
+++ b/src/testsuite/testsuite.c
@@ -179,8 +179,10 @@ int main(int argc, char **argv)
 		scriptenv.user = sieve_tool_get_mail_user(sieve_tool);
 		scriptenv.default_mailbox = "INBOX";
 		scriptenv.postmaster_address = "postmaster@example.com";
-		scriptenv.smtp_open = testsuite_smtp_open;
-		scriptenv.smtp_close = testsuite_smtp_close;
+		scriptenv.smtp_start = testsuite_smtp_start;
+		scriptenv.smtp_add_rcpt = testsuite_smtp_add_rcpt;
+		scriptenv.smtp_send = testsuite_smtp_send;
+		scriptenv.smtp_finish = testsuite_smtp_finish;
 		scriptenv.trace_stream = tracestream;
 		scriptenv.trace_config = tr_config;
 
diff --git a/tests/deprecated/notify/mailto.svtest b/tests/deprecated/notify/mailto.svtest
index cdbddf2dd4198dff7ef248450787c6a409db7c46..172433984f30ddfc12fa61c257fd0652e5c65afe 100644
--- a/tests/deprecated/notify/mailto.svtest
+++ b/tests/deprecated/notify/mailto.svtest
@@ -84,8 +84,8 @@ test "Multiple recipients" {
 		test_fail "auto-submitted header not found for third message";
 	}
 
-	if not address :count "eq" :comparator "i;ascii-numeric" "to" "1" {
-		test_fail "too many recipients in To header";
+	if not address :count "eq" :comparator "i;ascii-numeric" "to" "3" {
+		test_fail "wrong number of recipients in To header";
 	}
 
 	if not address :count "eq" :comparator "i;ascii-numeric" "cc" "0" {