using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; using System.IO; namespace FastReport.Export.Email { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] internal class MapiMessage { public int reserved; public string subject; public string noteText; public string messageType; public string dateReceived; public string conversationID; public int flags; public IntPtr originator; public int recipCount; public IntPtr recips; public int fileCount; public IntPtr files; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] internal class MapiRecipDesc { public int reserved; public int recipClass; public string name; public string address; public int eIDSize; public IntPtr entryID; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] internal class MapiFileDesc { public int reserved; public int flags; public int position; public string pathName; public string fileName; public IntPtr fileType; } /// /// Allows to send message using MAPI interface. /// public static class MAPI { #region static const int MapiLogonUI = 0x00000001; const int MAPI_DIALOG = 0x8; const int MAPI_TO = 1; const int MAPI_CC = 2; [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)] private static extern int MAPISendMail(IntPtr session, IntPtr uiParam, MapiMessage message, int flags, int reserved); [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)] private static extern int MAPILogon(IntPtr hwnd, string profileName, string password, int flags, int reserved, ref IntPtr session); [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)] private static extern int MAPILogoff(IntPtr session, IntPtr hwnd, int flags, int reserved); private static string[] errors = new string[] { "OK [0]", "User abort [1]", "General MAPI failure [2]", "MAPI login failure [3]", "Disk full [4]", "Insufficient memory [5]", "Access denied [6]", "-unknown- [7]", "Too many sessions [8]", "Too many files were specified [9]", "Too many recipients were specified [10]", "A specified attachment was not found [11]", "Attachment open failure [12]", "Attachment write failure [13]", "Unknown recipient [14]", "Bad recipient type [15]", "No messages [16]", "Invalid message [17]", "Text too large [18]", "Invalid session [19]", "Type not supported [20]", "A recipient was specified ambiguously [21]", "Message in use [22]", "Network failure [23]", "Invalid edit fields [24]", "Invalid recipients [25]", "Not supported [26]" }; #endregion private static MapiMessage CreateMessage(string[] files, string mailSubject, string mailBody, string[] recipientName, string[] recipientAddress) { MapiMessage msg = new MapiMessage(); msg.subject = mailSubject; msg.noteText = mailBody; if (files.Length > 0) { msg.fileCount = files.Length; msg.files = GetFilesDesc(files); } if (recipientAddress.Length > 0) { msg.recipCount = recipientAddress.Length; msg.recips = GetRecipDesc(recipientName, recipientAddress); } return msg; } private static IntPtr GetFilesDesc(string[] files) { IntPtr ptra = AllocMemory(typeof(MapiFileDesc), files.Length); for (int i = 0; i < files.Length; i++) { MapiFileDesc fileDesc = new MapiFileDesc(); fileDesc.position = -1; fileDesc.fileName = Path.GetFileName(files[i]); fileDesc.pathName = files[i]; Marshal.StructureToPtr(fileDesc, OffsetPtr(ptra, typeof(MapiFileDesc), files.Length - 1 - i), false); } return ptra; } private static IntPtr GetRecipDesc(string[] recipientName, string[] recipientAddress) { IntPtr ptra = AllocMemory(typeof(MapiRecipDesc), recipientAddress.Length); for (int i = 0; i < recipientAddress.Length; i++) { MapiRecipDesc recipDesc = new MapiRecipDesc(); recipDesc.recipClass = i == 0 ? MAPI_TO : MAPI_CC; if (recipientName.Length > i) recipDesc.name = recipientName[i]; recipDesc.address = recipientAddress[i]; Marshal.StructureToPtr(recipDesc, OffsetPtr(ptra, typeof(MapiRecipDesc), recipientAddress.Length - 1 - i), false); } return ptra; } private static IntPtr AllocMemory(Type structureType, int count) { return Marshal.AllocHGlobal(Marshal.SizeOf(structureType) * count); } private static IntPtr OffsetPtr(IntPtr ptr, Type structureType, int offset) { return (IntPtr)((long)ptr + offset * Marshal.SizeOf(structureType)); } private static void Logoff(IntPtr hwnd, IntPtr session) { if (session != IntPtr.Zero) { MAPILogoff(session, hwnd, 0, 0); session = IntPtr.Zero; } } private static bool Logon(IntPtr hwnd, ref IntPtr session) { int error = MAPILogon(hwnd, null, null, 0, 0, ref session); if (error != 0) error = MAPILogon(hwnd, null, null, MapiLogonUI, 0, ref session); return error == 0; } private static void DisposeMessage(MapiMessage msg) { FreeMemory(msg.files, typeof(MapiFileDesc), msg.fileCount); FreeMemory(msg.recips, typeof(MapiRecipDesc), msg.recipCount); msg = null; } private static void FreeMemory(IntPtr ptr, Type structureType, int count) { if (ptr != IntPtr.Zero) { for (int i = 0; i < count; i++) { Marshal.DestroyStructure(OffsetPtr(ptr, structureType, i), structureType); } Marshal.FreeHGlobal(ptr); } } /// /// Sends a message. /// /// Parent window handle. /// Files to attach. /// Email subject. /// Email body. /// Recipient names. /// Recipient addresses. /// Error code. 0 if operation was completed succesfully. public static int SendMail(IntPtr handle, string[] files, string mailSubject, string mailBody, string[] recipentName, string[] recipientAddress) { IntPtr session = IntPtr.Zero; int error = 0; if (Logon(handle, ref session)) { MapiMessage msg = CreateMessage(files, mailSubject, mailBody, recipentName, recipientAddress); error = MAPISendMail(session, handle, msg, MAPI_DIALOG, 0); Logoff(handle, session); DisposeMessage(msg); } return error; } /// /// Returns a text describing an error. /// /// The error code. /// The text describing an error. public static string GetErrorText(int error) { if (error <= 26) return errors[error]; return "MAPI error [" + error.ToString() + "]"; } } }