diff -Naur cyrus-imapd-2.1.18/imap/append.c cyrus-imapd-2.1.18.patched/imap/append.c
--- cyrus-imapd-2.1.18/imap/append.c	2003-09-02 22:11:33.000000000 +0300
+++ cyrus-imapd-2.1.18.patched/imap/append.c	2005-06-16 14:04:54.581571000 +0300
@@ -387,7 +387,7 @@
  * so it can double as the spool file
  */
 FILE *append_newstage(const char *mailboxname, time_t internaldate,
-		      struct stagemsg **stagep)
+		      int msgnum, struct stagemsg **stagep)
 {
     struct stagemsg *stage;
     char stagedir[MAX_MAILBOX_PATH+1], stagefile[MAX_MAILBOX_PATH+1];
@@ -401,8 +401,8 @@
     stage->parts = xzmalloc(5 * (MAX_MAILBOX_PATH+1) * sizeof(char));
     stage->partend = stage->parts + 5 * (MAX_MAILBOX_PATH+1) * sizeof(char);
 
-    snprintf(stage->fname, sizeof(stage->fname), "%d-%d",
-	     (int) getpid(), (int) internaldate);
+    snprintf(stage->fname, sizeof(stage->fname), "%d-%d-%d",
+	     (int) getpid(), (int) internaldate, msgnum);
 
     r = mboxlist_findstage(mailboxname, stagedir, sizeof(stagedir));
     if (r) {
@@ -445,10 +445,8 @@
  * is multiple partitions.
  */
 int append_fromstage(struct appendstate *as,
-		     struct protstream *messagefile,
-		     unsigned long size, time_t internaldate,
-		     const char **flag, int nflags,
-		     struct stagemsg *stage)
+		struct stagemsg *stage, time_t internaldate,
+		const char **flag, int nflags, int nolink)
 {
     struct mailbox *mailbox = &as->m;
     struct index_record message_index;
@@ -464,7 +462,6 @@
 
     assert(stage != NULL && stage->parts[0] != '\0');
     assert(mailbox->format == MAILBOX_FORMAT_NORMAL);
-    assert(size != 0);
 
     zero_index(message_index);
 
@@ -494,7 +491,7 @@
 	   make sure not to overwrite stage->partend */
 
 	/* create the new staging file from the first stage part */
-	r = mailbox_copyfile(stage->parts, stagefile);
+	r = mailbox_copyfile(stage->parts, stagefile, 0);
 	if (r) {
 	    /* maybe the directory doesn't exist? */
 	    char stagedir[MAX_MAILBOX_PATH+1];
@@ -507,7 +504,7 @@
 	    } else {
 		syslog(LOG_NOTICE, "created stage directory %s",
 		       stagedir);
-		r = mailbox_copyfile(stage->parts, stagefile);
+		r = mailbox_copyfile(stage->parts, stagefile, 0);
 	    }
 	}
 	if (r) {
@@ -550,7 +547,7 @@
 			      fname + strlen(fname),
 			      sizeof(fname) - strlen(fname));
 
-    r = mailbox_copyfile(p, fname);
+    r = mailbox_copyfile(p, fname, nolink);
     destfile = fopen(fname, "r");
     if (!r && destfile) {
 	/* ok, we've successfully created the file */
@@ -839,7 +836,7 @@
 	    mailbox_message_get_fname(mailbox, copymsg[msg].uid, fnamebuf,
 				      sizeof(fnamebuf));
 	    /* Link/copy message file */
-	    r = mailbox_copyfile(fnamebuf, fname);
+	    r = mailbox_copyfile(fnamebuf, fname, 0);
 	    if (r) goto fail;
 
 	    /* Write out cache info, copy other info */
diff -Naur cyrus-imapd-2.1.18/imap/append.h cyrus-imapd-2.1.18.patched/imap/append.h
--- cyrus-imapd-2.1.18/imap/append.h	2003-04-15 18:33:56.000000000 +0300
+++ cyrus-imapd-2.1.18.patched/imap/append.h	2005-06-16 14:04:54.583717000 +0300
@@ -113,14 +113,13 @@
 
 /* creates a new stage and returns stage file corresponding to mailboxname */
 extern FILE *append_newstage(const char *mailboxname, time_t internaldate,
-			     struct stagemsg **stagep);
+			     int msgnum, struct stagemsg **stagep);
 
 /* adds a new mailbox to the stage initially created by append_newstage() */
 extern int append_fromstage(struct appendstate *mailbox,
-			    struct protstream *messagefile,
-			    unsigned long size, time_t internaldate,
-			    const char **flag, int nflags,
-			    struct stagemsg *stage);
+		struct stagemsg *stage, time_t internaldate,
+	 	const char **flag, int nflags, int nolink);
+
 
 /* removes the stage (frees memory, deletes the staging files) */
 extern int append_removestage(struct stagemsg *stage);
diff -Naur cyrus-imapd-2.1.18/imap/imapd.c cyrus-imapd-2.1.18.patched/imap/imapd.c
--- cyrus-imapd-2.1.18/imap/imapd.c	2005-02-19 16:46:26.000000000 +0200
+++ cyrus-imapd-2.1.18.patched/imap/imapd.c	2005-06-18 20:44:37.690907000 +0300
@@ -80,6 +80,7 @@
 #include "imparse.h"
 #include "iptostring.h"
 #include "mailbox.h"
+#include "message.h"
 #include "mboxname.h"
 #include "mboxlist.h"
 #include "mbdump.h"
@@ -2358,23 +2359,26 @@
     int nflags = 0, flagalloc = 0;
     static struct buf arg;
     char *p;
-    time_t internaldate;
-    unsigned size = 0;
+    time_t internaldate, now = time(NULL);
+    unsigned size, totalsize = 0;
     int sawdigit = 0;
     int isnowait = 0;
-    int r;
+    int r, i;
     char mailboxname[MAX_MAILBOX_NAME+1];
     struct appendstate mailbox;
     unsigned long uidvalidity;
-    unsigned long firstuid, num;
+    unsigned long firstuid, num = 0;
     const char *parseerr = NULL;
+    FILE *f;
+    int numalloc = 5;
+    struct stagemsg **stage = xmalloc(numalloc * sizeof(struct stagemsg *));
 
-    /* Set up the append */
+    /* See if we can append */
     r = (*imapd_namespace.mboxname_tointernal)(&imapd_namespace, name,
 					       imapd_userid, mailboxname);
     if (!r) {
-	r = append_setup(&mailbox, mailboxname, MAILBOX_FORMAT_NORMAL,
-			 imapd_userid, imapd_authstate, ACL_INSERT, size);
+	r = append_check(mailboxname, MAILBOX_FORMAT_NORMAL,
+			 imapd_authstate, ACL_INSERT, totalsize);
     }
     if (r) {
 	eatline(imapd_in, ' ');
@@ -2487,10 +2491,22 @@
 	    prot_flush(imapd_out);
 	}
 	
-	/* Perform the rest of the append */
-	if (!r) r = append_fromstream(&mailbox, imapd_in, size, internaldate, 
-				      (const char **) flag, nflags);
-
+	/* Stage the message */
+	if (num == numalloc) {
+	    numalloc *= 2;
+	    stage = xrealloc(stage, numalloc * sizeof(struct stagemsg *));
+	}
+	stage[num] = NULL;
+	f = append_newstage(mailboxname, now, num, &stage[num]);
+	if (f) {
+	    num++;
+	    totalsize += size;
+	    r = message_copy_strict(imapd_in, f, size);
+	    fclose(f);
+	} else {
+	    r = IMAP_IOERROR;
+	}
+	
 	/* if we see a SP, we're trying to append more than one message */
 
 	/* Parse newline terminating command */
@@ -2510,11 +2526,27 @@
 	}
     }
 
+    /* Append from the stage(s) */
     if (!r) {
-	r = append_commit(&mailbox, &uidvalidity, &firstuid, &num);
-    } else {
-	append_abort(&mailbox);
+ 	r = append_setup(&mailbox, mailboxname, MAILBOX_FORMAT_NORMAL,
+ 			 imapd_userid, imapd_authstate, ACL_INSERT, totalsize);
+ 	for (i = 0; !r && i < num; i++) {
+ 	    r = append_fromstage(&mailbox, stage[i], internaldate, 
+ 				 (const char **) flag, nflags, 0);
+ 	}
+ 
+ 	if (!r) {
+ 	    r = append_commit(&mailbox, &uidvalidity, &firstuid, &num);
+ 	} else {
+ 	    append_abort(&mailbox);
+ 	}
+     }
+ 
+     /* Cleanup the stage(s) */
+     for (i = 0; i < num; i++) {
+ 	append_removestage(stage[i]);
     }
+     free(stage);
 
     if (imapd_mailbox) {
 	index_check(imapd_mailbox, 0, 0);
diff -Naur cyrus-imapd-2.1.18/imap/lmtpd.c cyrus-imapd-2.1.18.patched/imap/lmtpd.c
--- cyrus-imapd-2.1.18/imap/lmtpd.c	2005-02-19 18:26:18.000000000 +0200
+++ cyrus-imapd-2.1.18.patched/imap/lmtpd.c	2005-06-16 14:04:54.613648000 +0300
@@ -1147,13 +1147,8 @@
 
     if (!r) {
 	prot_rewind(msg);
-	if (stage) {
-	    r = append_fromstage(&as, msg, size, now, 
-				 (const char **) flag, nflags, stage);
-	} else {
-	    r = append_fromstream(&as, msg, size, now, 
-				  (const char **) flag, nflags);
-	}
+	r = append_fromstage(&as, stage, now,
+			     (const char **) flag, nflags, !singleinstance);
 	if (!r) append_commit(&as, NULL, NULL, NULL);
 	else append_abort(&as);
     }
@@ -1492,17 +1487,19 @@
 
 FILE *spoolfile(message_data_t *msgdata)
 {
-    /* if we have a single recipient OR are using single-instance store,
-     * spool to the stage of the first recipient
-     */
-    if ((msg_getnumrcpt(msgdata) == 1) || singleinstance) {
+     int i, n;
+     time_t now = time(NULL);
+     FILE *f = NULL;
+ 
+     /* spool to the stage of one of the recipients */
+     n = msg_getnumrcpt(msgdata);
+     for (i = 0; !f && (i < n); i++) {
 	int r = 0;
 	char *rcpt, *plus, *user = NULL;
 	char namebuf[MAX_MAILBOX_PATH+1], mailboxname[MAX_MAILBOX_PATH+1];
-	time_t now = time(NULL);
 
 	/* build the mailboxname from the recipient address */
-	rcpt = xstrdup(msg_getrcpt(msgdata, 0));
+	rcpt = xstrdup(msg_getrcpt(msgdata, i));
 	plus = strchr(rcpt, '+');
 	if (plus) *plus++ = '\0';
 
@@ -1540,19 +1537,15 @@
 	free(rcpt);
 
 	if (!r) {
-	    FILE *f;
 	    struct stagemsg *stage = NULL;
 
 	    /* setup stage for later use by deliver() */
-	    f = append_newstage(mailboxname, now, &stage);
+	    f = append_newstage(mailboxname, now, 0, &stage);
 	    msg_setrock(msgdata, (void*) stage);
-
-	    return f;
 	}
     }
 
-    /* spool to /tmp (no single-instance store) */
-    return tmpfile();
+    return f;
 }
 
 void removespool(message_data_t *msgdata)
diff -Naur cyrus-imapd-2.1.18/imap/mailbox.c cyrus-imapd-2.1.18.patched/imap/mailbox.c
--- cyrus-imapd-2.1.18/imap/mailbox.c	2003-11-04 23:43:00.000000000 +0200
+++ cyrus-imapd-2.1.18.patched/imap/mailbox.c	2005-06-16 14:04:54.622963000 +0300
@@ -2401,13 +2401,13 @@
     strlcpy(newfnametail, FNAME_INDEX, sizeof(newfname) - newfname_len);
     unlink(newfname);		/* Make link() possible */
 
-    r = mailbox_copyfile(oldfname, newfname);
+    r = mailbox_copyfile(oldfname, newfname, 0);
 
     strlcpy(oldfnametail, FNAME_CACHE, sizeof(oldfname) - oldfname_len);
     strlcpy(newfnametail, FNAME_CACHE, sizeof(newfname) - newfname_len);
     unlink(newfname);
 
-    if (!r) r = mailbox_copyfile(oldfname, newfname);
+    if (!r) r = mailbox_copyfile(oldfname, newfname, 0);
     if (r) {
 	mailbox_close(newmailbox);
 	return r;
@@ -2437,7 +2437,7 @@
 
 	strcpy(newfnametail, oldfnametail);
 
-	r = mailbox_copyfile(oldfname, newfname);
+	r = mailbox_copyfile(oldfname, newfname, 0);
 	if (r) break;
     }
     if (!r) r = seen_copy(oldmailbox, newmailbox);
@@ -2627,7 +2627,7 @@
 				      oldfnametail,
 				      sizeof(oldfname) - strlen(oldfname));
 	    strcpy(newfnametail, oldfnametail);
-	    r = mailbox_copyfile(oldfname, newfname);
+	    r = mailbox_copyfile(oldfname, newfname, 0);
 	    if (r) break;
 	}
     }
@@ -2658,7 +2658,7 @@
 	        sizeof(newfname) - (newfname_len - 1));
 
 	unlink(newfname);		/* Make link() possible */
-	r = mailbox_copyfile(oldfname, newfname);
+	r = mailbox_copyfile(oldfname, newfname, 0);
 
 	fn_len = strlen(FNAME_CACHE);
 	if((oldfname_len - 1) + fn_len > sizeof(oldfname))
@@ -2680,7 +2680,7 @@
 	        sizeof(newfname) - (newfname_len - 1));
 
 	unlink(newfname);
-	if (!r) r = mailbox_copyfile(oldfname, newfname);
+	if (!r) r = mailbox_copyfile(oldfname, newfname, 0);
 
 	if (r) {
 	    mailbox_close(&newmailbox);
@@ -2745,9 +2745,7 @@
 /*
  * Copy (or link) the file 'from' to the file 'to'
  */
-int mailbox_copyfile(from, to)
-const char *from;
-const char *to;
+int mailbox_copyfile(const char *from, const char *to, int nolink)
 {
     int srcfd, destfd;
     struct stat sbuf;
@@ -2755,13 +2753,15 @@
     unsigned long src_size = 0;
     int n;
 
-    if (link(from, to) == 0) return 0;
-    if (errno == EEXIST) {
-	if (unlink(to) == -1) {
-	    syslog(LOG_ERR, "IOERROR: unlinking to recreate %s: %m", to);
-	    return IMAP_IOERROR;
-	}
+    if (!nolink) {
 	if (link(from, to) == 0) return 0;
+	if (errno == EEXIST) {
+	    if (unlink(to) == -1) {
+		syslog(LOG_ERR, "IOERROR: unlinking to recreate %s: %m", to);
+		return IMAP_IOERROR;
+	    }
+	    if (link(from, to) == 0) return 0;
+	}
     }
     
     destfd = open(to, O_RDWR|O_TRUNC|O_CREAT, 0666);
diff -Naur cyrus-imapd-2.1.18/imap/mailbox.h cyrus-imapd-2.1.18.patched/imap/mailbox.h
--- cyrus-imapd-2.1.18/imap/mailbox.h	2003-03-31 23:15:05.000000000 +0300
+++ cyrus-imapd-2.1.18.patched/imap/mailbox.h	2005-06-16 14:04:54.626274000 +0300
@@ -314,7 +314,7 @@
 			bit32 *olduidvalidityp, bit32 *newuidvalidtyp,
 			struct mailbox *mailboxp);
 
-extern int mailbox_copyfile(const char *from, const char *to);
+extern int mailbox_copyfile(const char *from, const char *to, int nolink);
 extern void mailbox_hash_mbox(char *buf, size_t buf_len,
 			      const char *root, const char *name);
 
diff -Naur cyrus-imapd-2.1.18/imap/seen_local.c cyrus-imapd-2.1.18.patched/imap/seen_local.c
--- cyrus-imapd-2.1.18/imap/seen_local.c	2005-02-14 08:45:19.000000000 +0200
+++ cyrus-imapd-2.1.18.patched/imap/seen_local.c	2005-06-16 14:04:54.629410000 +0300
@@ -446,7 +446,7 @@
     strlcat(oldfname, FNAME_SEEN, sizeof(oldfname));
     strlcpy(newfname, newmailbox->path, sizeof(newfname));
     strlcat(newfname, FNAME_SEEN, sizeof(newfname));
-    return mailbox_copyfile(oldfname, newfname);
+    return mailbox_copyfile(oldfname, newfname, 0);
 }
 
 /*
