Wednesday, October 17, 2007

Adding an attachment in a Transport Agent on Exchange 2007

This is a quick post to give an example of something that from the outset I would have thought would be easy but for some reason took me a little time to get my head around. Having been using CDOSYS/EX for a number of years adding a attachment to a message Is as easy as just using the addattachment method and specifying the filepath and the class will do the rest and add that attachment to the message. When working in a transport agent with the Microsoft.Exchange.Data.Transport.Email class to add an attachment you can use the attachment collections add method. There is an overload for this method that allows you to specify the filename which I thought would mean that this would work like CDOSYS’s addattachment method which didn’t turn out to be the case. Using this overload just gives you a blank attachment object with the filename property set. So to add an attachment within a Transport agent you first need to open the file in question and read-in the stream of bytes from the file and then write that stream into the attachment objects stream and then make sure you flush the attachment stream to have it committed to the message.

The following is a partial code sample of adding a word document as an attachment to a message in a Transport Agent.

void EmailAddAttachmentAgent_OnSubmittedMessage(SubmittedMessageEventSource source, QueuedMessageEventArgs e)
{

Attachment newattach = e.MailItem.Message.Attachments.Add("answer.doc");
Stream fsFileStream1 = new FileStream(@"C:\temp\answer.doc", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
byte[] bytes1 = ReadFully(fsFileStream1, (int)fsFileStream1.Length);
Stream newattachstream = newattach.GetContentWriteStream();
newattachstream.Write(bytes1, 0, bytes1.Length);
newattachstream.Flush();
newattachstream.Close();

}

public static byte[] ReadFully(Stream stream, int initialLength)

{

// ref Function from http://www.yoda.arachsys.com/csharp/readbinary.html
// If we've been passed an unhelpful initial length, just
// use 32K.
if (initialLength < 1)
{
initialLength = 32768;
}
byte[] buffer = new byte[initialLength];
int read = 0;
int chunk;
while ((chunk = stream.Read(buffer, read, buffer.Length - read)) > 0)

{
read += chunk;

// If we've reached the end of our buffer, check to see if there's
// any more information
if (read == buffer.Length)
{

int nextByte = stream.ReadByte();
// End of stream? If so, we're done
if (nextByte == -1)

{
return buffer;
}

// Nope. Resize the buffer, put in the byte we've just
// read, and continue
byte[] newBuffer = new byte[buffer.Length * 2];
Array.Copy(buffer, newBuffer, buffer.Length);
newBuffer[read] = (byte)nextByte;
buffer = newBuffer;
read++;

}

}

// Buffer is now too big. Shrink it.

byte[] ret = new byte[read];
Array.Copy(buffer, ret, read);
return ret;

}