//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ /* * Simple SMTP send mail utility * * Copyright (c) 2000, Microsoft Corporation */ namespace System.Web.Mail { using System; using System.Collections; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.InteropServices; using System.Runtime.Serialization.Formatters; using System.Security.Permissions; using System.Text; using System.Web.Hosting; using System.Web.Management; using System.Web.Util; /* * Class that sends MailMessage using CDONTS/CDOSYS */ /// /// [To be supplied.] /// [Obsolete("The recommended alternative is System.Net.Mail.SmtpClient. http://go.microsoft.com/fwlink/?linkid=14202")] public class SmtpMail { private static object _lockObject = new object(); private SmtpMail() { } #if !FEATURE_PAL // FEATURE_PAL does not enable SmtpMail // // Late bound helper // internal class LateBoundAccessHelper { private String _progId; private Type _type; internal LateBoundAccessHelper(String progId) { _progId = progId; } private Type LateBoundType { get { if (_type == null) { try { _type = Type.GetTypeFromProgID(_progId); } catch { } if (_type == null) throw new HttpException(SR.GetString(SR.SMTP_TypeCreationError, _progId)); } return _type; } } internal Object CreateInstance() { return Activator.CreateInstance(LateBoundType); } internal Object CallMethod(Object obj, String methodName, Object[] args) { try { return CallMethod(LateBoundType, obj, methodName, args); } catch (Exception e) { throw new HttpException(GetInnerMostException(e).Message, e); } } internal static Object CallMethodStatic(Object obj, String methodName, Object[] args) { return CallMethod(obj.GetType(), obj, methodName, args); } private static Object CallMethod(Type type, Object obj, String methodName, Object[] args) { return type.InvokeMember(methodName, BindingFlags.InvokeMethod, null, obj, args, CultureInfo.InvariantCulture); } private static Exception GetInnerMostException(Exception e) { if (e.InnerException == null) return e; else return GetInnerMostException(e.InnerException); } internal Object GetProp(Object obj, String propName) { try { return GetProp(LateBoundType, obj, propName); } catch (Exception e) { throw new HttpException(GetInnerMostException(e).Message, e); } } internal static Object GetPropStatic(Object obj, String propName) { return GetProp(obj.GetType(), obj, propName); } private static Object GetProp(Type type, Object obj, String propName) { return type.InvokeMember(propName, BindingFlags.GetProperty, null, obj,new Object[0], CultureInfo.InvariantCulture); } internal void SetProp(Object obj, String propName, Object propValue) { try { SetProp(LateBoundType, obj, propName, propValue); } catch (Exception e) { throw new HttpException(GetInnerMostException(e).Message, e); } } internal static void SetPropStatic(Object obj, String propName, Object propValue) { SetProp(obj.GetType(), obj, propName, propValue); } private static void SetProp(Type type, Object obj, String propName, Object propValue) { if (propValue != null && (propValue is string) && ((string)propValue).IndexOf('\0') >= 0) throw new ArgumentException(); type.InvokeMember(propName, BindingFlags.SetProperty, null, obj, new Object[1] { propValue }, CultureInfo.InvariantCulture); } internal void SetProp(Object obj, String propName, Object propKey, Object propValue) { try { SetProp(LateBoundType, obj, propName, propKey, propValue); } catch (Exception e) { throw new HttpException(GetInnerMostException(e).Message, e); } } internal static void SetPropStatic(Object obj, String propName, Object propKey, Object propValue) { SetProp(obj.GetType(), obj, propName, propKey, propValue); } private static void SetProp(Type type, Object obj, String propName, Object propKey, Object propValue) { if (propValue != null && (propValue is string) && ((string)propValue).IndexOf('\0') >= 0) throw new ArgumentException(); type.InvokeMember(propName, BindingFlags.SetProperty, null, obj,new Object[2] { propKey, propValue }, CultureInfo.InvariantCulture); } } // // Late bound access to CDONTS // internal class CdoNtsHelper { private static LateBoundAccessHelper _helper = new LateBoundAccessHelper("CDONTS.NewMail"); private CdoNtsHelper() { } internal static void Send(MailMessage message) { // create mail object Object newMail = _helper.CreateInstance(); // set properties if (message.From != null) _helper.SetProp(newMail, "From", message.From); if (message.To != null) _helper.SetProp(newMail, "To", message.To); if (message.Cc != null) _helper.SetProp(newMail, "Cc", message.Cc); if (message.Bcc != null) _helper.SetProp(newMail, "Bcc", message.Bcc); if (message.Subject != null) _helper.SetProp(newMail, "Subject", message.Subject); if (message.Priority != MailPriority.Normal) { int p = 0; switch (message.Priority) { case MailPriority.Low: p = 0; break; case MailPriority.Normal: p = 1; break; case MailPriority.High: p = 2; break; } _helper.SetProp(newMail, "Importance", p); } if (message.BodyEncoding != null) _helper.CallMethod(newMail, "SetLocaleIDs", new Object[1] { message.BodyEncoding.CodePage }); if (message.UrlContentBase != null) _helper.SetProp(newMail, "ContentBase", message.UrlContentBase); if (message.UrlContentLocation != null) _helper.SetProp(newMail, "ContentLocation", message.UrlContentLocation); int numHeaders = message.Headers.Count; if (numHeaders > 0) { IDictionaryEnumerator e = message.Headers.GetEnumerator(); while (e.MoveNext()) { String k = (String)e.Key; String v = (String)e.Value; _helper.SetProp(newMail, "Value", k, v); } } if (message.BodyFormat == MailFormat.Html) { _helper.SetProp(newMail, "BodyFormat", 0); _helper.SetProp(newMail, "MailFormat", 0); } // always set Body (VSWhidbey 176284) _helper.SetProp(newMail, "Body", (message.Body != null) ? message.Body : String.Empty); for (IEnumerator e = message.Attachments.GetEnumerator(); e.MoveNext(); ) { MailAttachment a = (MailAttachment)e.Current; int c = 0; switch (a.Encoding) { case MailEncoding.UUEncode: c = 0; break; case MailEncoding.Base64: c = 1; break; } _helper.CallMethod(newMail, "AttachFile", new Object[3] { a.Filename, null, (Object)c }); } // send mail _helper.CallMethod(newMail, "Send", new Object[5] { null, null, null, null, null }); // close unmanaged COM classic component Marshal.ReleaseComObject(newMail); } internal static void Send(String from, String to, String subject, String messageText) { MailMessage m = new MailMessage(); m.From = from; m.To = to; m.Subject = subject; m.Body = messageText; Send(m); } } // // Late bound access to CDOSYS // internal class CdoSysHelper { private static LateBoundAccessHelper _helper = new LateBoundAccessHelper("CDO.Message"); enum CdoSysLibraryStatus { NotChecked, Exists, DoesntExist } // Variable that shows if cdosys.dll exists private static CdoSysLibraryStatus cdoSysLibraryInfo = CdoSysLibraryStatus.NotChecked; private CdoSysHelper() { } private static void SetField(Object m, String name, String value) { _helper.SetProp(m, "Fields", "urn:schemas:mailheader:" + name, value); Object fields = _helper.GetProp(m, "Fields"); LateBoundAccessHelper.CallMethodStatic(fields, "Update", new Object[0]); Marshal.ReleaseComObject(fields); } private static bool CdoSysExists() { // Check that the cdosys.dll exists if(cdoSysLibraryInfo == CdoSysLibraryStatus.NotChecked) { string fullDllPath = PathUtil.GetSystemDllFullPath("cdosys.dll"); IntPtr cdoSysModule = UnsafeNativeMethods.LoadLibrary(fullDllPath); if(cdoSysModule != IntPtr.Zero) { UnsafeNativeMethods.FreeLibrary(cdoSysModule); cdoSysLibraryInfo = CdoSysLibraryStatus.Exists; return true; } cdoSysLibraryInfo = CdoSysLibraryStatus.DoesntExist; return false; } // return cached value, found at a previous check return (cdoSysLibraryInfo == CdoSysLibraryStatus.Exists); } internal static bool OsSupportsCdoSys() { Version osVersion = Environment.OSVersion.Version; if ((osVersion.Major >= 7 || (osVersion.Major == 6 && osVersion.Minor >= 1))) { // for some OS versions higher that 6, CdoSys.dll doesn't exist return CdoSysExists(); } return true; } internal static void Send(MailMessage message) { // create message object Object m = _helper.CreateInstance(); // set properties if (message.From != null) _helper.SetProp(m, "From", message.From); if (message.To != null) _helper.SetProp(m, "To", message.To); if (message.Cc != null) _helper.SetProp(m, "Cc", message.Cc); if (message.Bcc != null) _helper.SetProp(m, "Bcc", message.Bcc); if (message.Subject != null) _helper.SetProp(m, "Subject", message.Subject); if (message.Priority != MailPriority.Normal) { String importance = null; switch (message.Priority) { case MailPriority.Low: importance = "low"; break; case MailPriority.Normal: importance = "normal"; break; case MailPriority.High: importance = "high"; break; } if (importance != null) SetField(m, "importance", importance); } if (message.BodyEncoding != null) { Object body = _helper.GetProp(m, "BodyPart"); LateBoundAccessHelper.SetPropStatic(body, "Charset", message.BodyEncoding.BodyName); Marshal.ReleaseComObject(body); } if (message.UrlContentBase != null) SetField(m, "content-base", message.UrlContentBase); if (message.UrlContentLocation != null) SetField(m, "content-location", message.UrlContentLocation); int numHeaders = message.Headers.Count; if (numHeaders > 0) { IDictionaryEnumerator e = message.Headers.GetEnumerator(); while (e.MoveNext()) { SetField(m, (String)e.Key, (String)e.Value); } } if (message.Body != null) { if (message.BodyFormat == MailFormat.Html) { _helper.SetProp(m, "HtmlBody", message.Body); } else { _helper.SetProp(m, "TextBody", message.Body); } } else { _helper.SetProp(m, "TextBody", String.Empty); } for (IEnumerator e = message.Attachments.GetEnumerator(); e.MoveNext(); ) { MailAttachment a = (MailAttachment)e.Current; Object bodyPart = _helper.CallMethod(m, "AddAttachment", new Object[3] { a.Filename, null, null }); if (a.Encoding == MailEncoding.UUEncode) _helper.SetProp(m, "MimeFormatted", false); if (bodyPart != null) Marshal.ReleaseComObject(bodyPart); } // optional SMTP server string server = SmtpMail.SmtpServer; if (!String.IsNullOrEmpty(server) || message.Fields.Count > 0) { Object config = LateBoundAccessHelper.GetPropStatic(m, "Configuration"); if (config != null) { LateBoundAccessHelper.SetPropStatic(config, "Fields", "http://schemas.microsoft.com/cdo/configuration/sendusing", (Object)2); LateBoundAccessHelper.SetPropStatic(config, "Fields", "http://schemas.microsoft.com/cdo/configuration/smtpserverport", (Object)25); if (!String.IsNullOrEmpty(server)) { LateBoundAccessHelper.SetPropStatic(config, "Fields", "http://schemas.microsoft.com/cdo/configuration/smtpserver", server); } foreach (DictionaryEntry e in message.Fields) { LateBoundAccessHelper.SetPropStatic(config, "Fields", (String)e.Key, e.Value); } Object fields = LateBoundAccessHelper.GetPropStatic(config, "Fields"); LateBoundAccessHelper.CallMethodStatic(fields, "Update", new Object[0]); Marshal.ReleaseComObject(fields); Marshal.ReleaseComObject(config); } } if (HostingEnvironment.IsHosted) { // revert to process identity while sending mail using (new ProcessImpersonationContext()) { // send mail _helper.CallMethod(m, "Send", new Object[0]); } } else { // send mail _helper.CallMethod(m, "Send", new Object[0]); } // close unmanaged COM classic component Marshal.ReleaseComObject(m); } internal static void Send(String from, String to, String subject, String messageText) { MailMessage m = new MailMessage(); m.From = from; m.To = to; m.Subject = subject; m.Body = messageText; Send(m); } } #endif // !FEATURE_PAL private static String _server; /// /// [To be supplied.] /// public static String SmtpServer { get { String s = _server; return (s != null) ? s : String.Empty; } set { _server = value; } } /// /// [To be supplied.] /// [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Medium)] [SecurityPermission(SecurityAction.Assert, UnmanagedCode=true)] public static void Send(String from, String to, String subject, String messageText) { lock (_lockObject) { #if !FEATURE_PAL // FEATURE_PAL does not enable SmtpMail if (Environment.OSVersion.Platform != PlatformID.Win32NT) { throw new PlatformNotSupportedException(SR.GetString(SR.RequiresNT)); } else if (!CdoSysHelper.OsSupportsCdoSys()) { throw new PlatformNotSupportedException(SR.GetString(SR.SmtpMail_not_supported_on_Win7_and_higher)); } else if (Environment.OSVersion.Version.Major <= 4) { CdoNtsHelper.Send(from, to, subject, messageText); } else { CdoSysHelper.Send(from, to, subject, messageText); } #else // !FEATURE_PAL throw new NotImplementedException("ROTORTODO"); #endif // !FEATURE_PAL } } /// /// [To be supplied.] /// [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Medium)] [SecurityPermission(SecurityAction.Assert, UnmanagedCode=true)] public static void Send(MailMessage message) { lock (_lockObject) { #if !FEATURE_PAL // FEATURE_PAL does not enable SmtpMail if (Environment.OSVersion.Platform != PlatformID.Win32NT) { throw new PlatformNotSupportedException(SR.GetString(SR.RequiresNT)); } else if (!CdoSysHelper.OsSupportsCdoSys()) { throw new PlatformNotSupportedException(SR.GetString(SR.SmtpMail_not_supported_on_Win7_and_higher)); } else if (Environment.OSVersion.Version.Major <= 4) { CdoNtsHelper.Send(message); } else { CdoSysHelper.Send(message); } #else // !FEATURE_PAL throw new NotImplementedException("ROTORTODO"); #endif // !FEATURE_PAL } } } // // Enums for message elements // /// /// [To be supplied.] /// [Obsolete("The recommended alternative is System.Net.Mail.MailMessage.IsBodyHtml. http://go.microsoft.com/fwlink/?linkid=14202")] public enum MailFormat { /// /// [To be supplied.] /// Text = 0, // note - different from CDONTS.NewMail /// /// [To be supplied.] /// Html = 1 } /// /// [To be supplied.] /// [Obsolete("The recommended alternative is System.Net.Mail.MailPriority. http://go.microsoft.com/fwlink/?linkid=14202")] public enum MailPriority { /// /// [To be supplied.] /// Normal = 0, // note - different from CDONTS.NewMail /// /// [To be supplied.] /// Low = 1, /// /// [To be supplied.] /// High = 2 } /// /// [To be supplied.] /// [Obsolete("The recommended alternative is System.Net.Mime.TransferEncoding. http://go.microsoft.com/fwlink/?linkid=14202")] public enum MailEncoding { /// /// [To be supplied.] /// UUEncode = 0, // note - same as CDONTS.NewMail /// /// [To be supplied.] /// Base64 = 1 } /* * Immutable struct that holds a single attachment */ /// /// [To be supplied.] /// [Obsolete("The recommended alternative is System.Net.Mail.Attachment. http://go.microsoft.com/fwlink/?linkid=14202")] public class MailAttachment { private String _filename; private MailEncoding _encoding; /// /// [To be supplied.] /// public String Filename { get { return _filename; } } /// /// [To be supplied.] /// public MailEncoding Encoding { get { return _encoding; } } /// /// [To be supplied.] /// public MailAttachment(String filename) { _filename = filename; _encoding = MailEncoding.Base64; VerifyFile(); } /// /// [To be supplied.] /// public MailAttachment(String filename, MailEncoding encoding) { _filename = filename; _encoding = encoding; VerifyFile(); } private void VerifyFile() { try { File.Open(_filename, FileMode.Open, FileAccess.Read, FileShare.Read).Close(); } catch { throw new HttpException(SR.GetString(SR.Bad_attachment, _filename)); } } } /* * Struct that holds a single message */ /// /// [To be supplied.] /// [Obsolete("The recommended alternative is System.Net.Mail.MailMessage. http://go.microsoft.com/fwlink/?linkid=14202")] public class MailMessage { Hashtable _headers = new Hashtable(); Hashtable _fields = new Hashtable(); ArrayList _attachments = new ArrayList(); string from; string to; string cc; string bcc; string subject; MailPriority priority = MailPriority.Normal; string urlContentBase; string urlContentLocation; string body; MailFormat bodyFormat = MailFormat.Text; Encoding bodyEncoding = Encoding.Default; /// /// [To be supplied.] /// public string From { get { return from; } set { from = value; } } /// /// [To be supplied.] /// public string To { get { return to; } set { to = value; } } /// /// [To be supplied.] /// public string Cc { get { return cc; } set { cc = value; } } /// /// [To be supplied.] /// public string Bcc { get { return bcc; } set { bcc = value; } } /// /// [To be supplied.] /// public string Subject { get { return subject; } set { subject = value; } } /// /// [To be supplied.] /// public MailPriority Priority { get { return priority; } set { priority = value; } } /// /// [To be supplied.] /// public string UrlContentBase { get { return urlContentBase; } set { urlContentBase = value; } } /// /// [To be supplied.] /// public string UrlContentLocation { get { return urlContentLocation; } set { urlContentLocation = value; } } /// /// [To be supplied.] /// public string Body { get { return body; } set { body = value; } } /// /// [To be supplied.] /// public MailFormat BodyFormat { get { return bodyFormat; } set { bodyFormat = value; } } /// /// [To be supplied.] /// public Encoding BodyEncoding { get { return bodyEncoding; } set { bodyEncoding = value; } } /// /// [To be supplied.] /// public IDictionary Headers { get { return _headers; } } /// /// [To be supplied.] /// public IDictionary Fields { get { return _fields; } } /// /// [To be supplied.] /// public IList Attachments { get { return _attachments; } } } }