因为项目中客户有一个的要求,所以这个Exchange前段时间搞的我很是头疼,没接触过这个东西,但是现在看来,纸老虎一个。希望我的经验可以帮助初次接触它的人少走一些弯路!
简单介绍一下:客户要求在自己的Exchange生产环境上创建一个传输规则,当用户邮件中包含有pdf类型的附件时,将这个附件下载到本地服务器,然后在加上可预览这个附件的链接(服务商提供的web应用程序而不是微软提供的的Office Web App Services)。
环境:一台DC,一台Exchange Server 2013服务器,建议8G内存至少
----------------------------------------------------------------------------------------
如何把邮件的附件Load下来网上应该很多源代码,基本上都是使用Exchange Web Service,简单说如下:
public void StripAttachments(ItemId id, string folder)
{
try
{
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013);
service.Credentials = new NetworkCredential("Administrator", "Password01!", "TEST.com");
service.Url = new Uri("https://192.168.1.116/ews/exchange.asmx");
EmailMessage email = EmailMessage.Bind(service, id);
foreach (Attachment attachment in email.Attachments)
{
if (attachment is FileAttachment)
{
if (attachment.Name.Contains("pdf"))
{
// do your thing
FileAttachment fileAttachment = attachment as FileAttachment;
fileAttachment.Load("C:\\temp\\" + fileAttachment.Name);
}
}
}
}
catch (Exception e)
{
//
}
对已经存在于收件箱的邮件使用它操作最好不过了,但是不符合我的要求。因为我要对所有经过边缘传输服务器的邮件进行操作。
微软对于用户自定义传输规则提供了两个方式SmtpReceiveAgent和RoutingAgent,我使用了后者。
namespace Microsoft.Exchange.Data.Transport.Routing
{
public abstract class QueuedMessageEventArgs : EventArgs
{
public abstract MailItem MailItem { get; }
}
}
QueuedMessageEventArgs的MailItem为我们提供了操作邮件的支持
声明一个继承自RoutingAgentFactory的类,重写CreateAgent方法
public sealed class MyRoutingFactory : RoutingAgentFactory
{
public override RoutingAgent CreateAgent(SmtpServer server)
{
RoutingAgent arcEmail = new EmailArchivingRoutingAgent();
return arcEmail;
}
}
声明一个操作类
public class EmailArchivingRoutingAgent : RoutingAgent
构造方法中绑定触发事件
public EmailArchivingRoutingAgent()
{
//Invoked by Exchange when the entire message has been Submitted.
base.OnSubmittedMessage += new SubmittedMessageEventHandler(EmailArchivingRoutingAgent_OnSubmittedMessage);
}
然后我们在EmailArchivingRoutingAgent_OnSubmittedMessage这个方法里面去写对邮件的具体操作。通过循环e.MailItem.Message.Attachments,访问所有附件对象,然后判断类型再保存。
public void EmailArchivingRoutingAgent_OnSubmittedMessage(SubmittedMessageEventSource source, QueuedMessageEventArgs e)
{
for (int index = e.MailItem.Message.Attachments.Count - 1; index >= 0; index--)
{
//Get Attachment
Microsoft.Exchange.Data.Transport.Email.Attachment atAttach = e.MailItem.Message.Attachments[index];
//Get FileName of this Attachment
String feFileExtension = string.Empty;
//Effective Attachment
if (atAttach.AttachmentType == Microsoft.Exchange.Data.Transport.Email.AttachmentType.Regular & atAttach.FileName != null)
{
feFileExtension = atAttach.FileName.Substring((atAttach.FileName.Length - 4), 4);
}
//Judge the type of Attachment
if (feFileExtension.ToLower() == ".pdf")
{
FileStream atFileStream = File.Create("E:\\Share\\" + atAttach.FileName);
Stream attachstream = atAttach.GetContentReadStream();
byte[] bytes = ReadFully(attachstream, (int)attachstream.Length);
//byte[] bytes = this.StreamToBytes(attachstream);
atFileStream.Write(bytes, 0, bytes.Length);
atFileStream.Close();
atFileStream = null;
bytes = null;
attachstream.Close();
attachstream = null;
atAttach = null;
//After load the Attachment,wirte a Link message into Body of mail
if (File.Exists("E:\\Share\\" + e.MailItem.Message.Attachments[index].FileName))
{
this.ChangeBodyOfMail(source, e,index);
e.MailItem.Message.Subject += " PDF 写在E盘了";
}
}
}
ReadFully是把GetContentReadStream()返回的流转化为byte[]的方法
public static byte[] ReadFully(Stream stream, int initalLength)
{
if (initalLength < 1)
{
//min size
initalLength = 32768;
}
byte[] buffer = new byte[initalLength];
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,putin 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;
}
当然,一般安全的写法不是直接使用GetContentReadStream(),而是使用TryGetContentReadStream(),如下: