开发者

Is there a simple way of sending an email with attachments using the default mail client?

My issue is that I need to attach files with C# to the default mail client and show it to the user, much like using mailto:.

I read this post on the subject, but there are several issues:

  1. I do not want to use mailto because attachments are not officially supported.
  2. When using System.Net.Mail and the SMTP class (code supplied in the accepted answer), I am not sure how to pop up the message for the user to handle instead of just mailing it. Not sure if this is even possible.
  3. Also when using the solution above (#2) I'm not sure how to get the user's email server.
  4. In an answer supplied further down, a Code Project solution is presented using a custom wrapper for MAPI32.DLL. The issue here is that the license agreement specified by the writer of the article for this solution conflicts with the requirements that I am under for my project.
  5. Due to time restrictions I cannot write my own MAPI wrapper

So, are there any other simple solutions t开发者_运维知识库o this problem? Is there another simple way to pop up the default mail client with the attachments pre-populated with .NET? Maybe another MAPI wrapper, but one with a VERY lenient license?


A .NET mapi wrapper is indeed the best solution - there are many results returned for a google of "mapi .net wrapper", I am sure one of these will have a suitable license:

  • http://www.codeproject.com/KB/IP/CMapiEx.aspx - CDDL license


If you are happy with attachments that are not embedded here's a whole lot of code that will do the job. This is more for others who may come looking than OP who I am certain must have already found an alternative. Add a comment if something is missing and I'll add the necessary stuff. Enjoy!

  public class MailMessage
  {
    #region Constants and Fields

    private readonly string _body;

    private readonly string _subject;

    private readonly List<MapiFileDesc> _attachments;

    private readonly List<MapiRecipDesc> _recipients;

    #endregion

    #region Constructors and Destructors

    private MailMessage()
    {
    }

    public MailMessage(
        string subject, string body, IEnumerable<MailAttachment> attachments, IEnumerable<MailRecipient> recipients)
    {
      this._subject = subject;
      this._body = body;

      this._attachments = new List<MapiFileDesc>();
      this._recipients = new List<MapiRecipDesc>();

      if (attachments != null)
      {
        foreach (var attachment in attachments)
        {
          _attachments.Add(attachment.GetMapiFileDesc());
        }
      }

      if (recipients != null)
      {
        foreach (var recipient in recipients)
        {
          _recipients.Add(recipient.GetMapiRecipDesc());
        }
      }
    }

    #endregion

    #region Public Methods

    public void ShowDialog()
    {
      int result = this.ShowMail();

      if (!IsSuccess(result))
      {
        throw new Exception(GetMapiErrorMessage(result));
      }
    }

    #endregion

    #region Methods

    private int ShowMail()
    {
      var message = new MapiMessage();

      message.Subject = this._subject;
      message.NoteText = this._body;

      int attachmentCount;
      message.Files = AllocMapiDescArray(_attachments, out attachmentCount);
      message.FileCount = attachmentCount;

      int recipientCount;
      message.Recipients = AllocMapiDescArray(_recipients, out recipientCount);
      message.RecipientCount = recipientCount;

      int error = Mapi32.MAPISendMail(IntPtr.Zero, IntPtr.Zero, message, Mapi32.MAPI_DIALOG, 0);

      DeallocMapiDescArray<MapiFileDesc>(message.Files, message.FileCount);
      DeallocMapiDescArray<MapiRecipDesc>(message.Recipients, message.RecipientCount);

      return error;
    }

    private static IntPtr AllocMapiDescArray<T>(ICollection<T> mapiDescCollection, out int mapiDescCount)
    {
      IntPtr mapiMapiDescArrayPtr = IntPtr.Zero;
      mapiDescCount = 0;

      if (mapiDescCollection != null && mapiDescCollection.Count > 0)
      {
        int mapiDescSize = Marshal.SizeOf(typeof(T));
        mapiMapiDescArrayPtr = Marshal.AllocHGlobal(mapiDescCollection.Count * mapiDescSize);

        var tmp = (int)mapiMapiDescArrayPtr;
        foreach (var mapiDesc in mapiDescCollection)
        {
          Marshal.StructureToPtr(mapiDesc, (IntPtr)tmp, false);
          tmp += mapiDescSize;
        }

        mapiDescCount = mapiDescCollection.Count;
      }

      return mapiMapiDescArrayPtr;
    }

    private static void DeallocMapiDescArray<T>(IntPtr mapiDescArrayPtr, int mapiDescArrayCount)
    {
      if (mapiDescArrayPtr != IntPtr.Zero)
      {
        int mapiDescSize = Marshal.SizeOf(typeof(T));

        var tmp = (int)mapiDescArrayPtr;
        for (int i = 0; i < mapiDescArrayCount; i++)
        {
          Marshal.DestroyStructure((IntPtr)tmp, typeof(T));
          tmp += mapiDescSize;
        }
        Marshal.FreeHGlobal(mapiDescArrayPtr);
      }
    }

    private static bool IsSuccess(int errorCode)
    {
      return (errorCode == Mapi32.SUCCESS_SUCCESS || errorCode == Mapi32.MAPI_USER_ABORT);
    }

    private static string GetMapiErrorMessage(int errorCode)
    {
      // This should be localized

      string error = string.Empty;

      switch (errorCode)
      {
        case Mapi32.MAPI_USER_ABORT:
          error = "User Aborted.";
          break;
        case Mapi32.MAPI_E_FAILURE:
          error = "MAPI Failure.";
          break;
        case Mapi32.MAPI_E_LOGIN_FAILURE:
          error = "Login Failure.";
          break;
        case Mapi32.MAPI_E_DISK_FULL:
          error = "MAPI Disk full.";
          break;
        case Mapi32.MAPI_E_INSUFFICIENT_MEMORY:
          error = "MAPI Insufficient memory.";
          break;
        case Mapi32.MAPI_E_BLK_TOO_SMALL:
          error = "MAPI Block too small.";
          break;
        case Mapi32.MAPI_E_TOO_MANY_SESSIONS:
          error = "MAPI Too many sessions.";
          break;
        case Mapi32.MAPI_E_TOO_MANY_FILES:
          error = "MAPI too many files.";
          break;
        case Mapi32.MAPI_E_TOO_MANY_RECIPIENTS:
          error = "MAPI too many recipients.";
          break;
        case Mapi32.MAPI_E_ATTACHMENT_NOT_FOUND:
          error = "MAPI Attachment not found.";
          break;
        case Mapi32.MAPI_E_ATTACHMENT_OPEN_FAILURE:
          error = "MAPI Attachment open failure.";
          break;
        case Mapi32.MAPI_E_ATTACHMENT_WRITE_FAILURE:
          error = "MAPI Attachment Write Failure.";
          break;
        case Mapi32.MAPI_E_UNKNOWN_RECIPIENT:
          error = "MAPI Unknown recipient.";
          break;
        case Mapi32.MAPI_E_BAD_RECIPTYPE:
          error = "MAPI Bad recipient type.";
          break;
        case Mapi32.MAPI_E_NO_MESSAGES:
          error = "MAPI No messages.";
          break;
        case Mapi32.MAPI_E_INVALID_MESSAGE:
          error = "MAPI Invalid message.";
          break;
        case Mapi32.MAPI_E_TEXT_TOO_LARGE:
          error = "MAPI Text too large.";
          break;
        case Mapi32.MAPI_E_INVALID_SESSION:
          error = "MAPI Invalid session.";
          break;
        case Mapi32.MAPI_E_TYPE_NOT_SUPPORTED:
          error = "MAPI Type not supported.";
          break;
        case Mapi32.MAPI_E_AMBIGUOUS_RECIPIENT:
          error = "MAPI Ambiguous recipient.";
          break;
        case Mapi32.MAPI_E_MESSAGE_IN_USE:
          error = "MAPI Message in use.";
          break;
        case Mapi32.MAPI_E_NETWORK_FAILURE:
          error = "MAPI Network failure.";
          break;
        case Mapi32.MAPI_E_INVALID_EDITFIELDS:
          error = "MAPI Invalid edit fields.";
          break;
        case Mapi32.MAPI_E_INVALID_RECIPS:
          error = "MAPI Invalid Recipients.";
          break;
        case Mapi32.MAPI_E_NOT_SUPPORTED:
          error = "MAPI Not supported.";
          break;
        case Mapi32.MAPI_E_NO_LIBRARY:
          error = "MAPI No Library.";
          break;
        case Mapi32.MAPI_E_INVALID_PARAMETER:
          error = "MAPI Invalid parameter.";
          break;
      }

      return string.Format("Error sending email. Error: {0} (code = {1}).", error, errorCode);
    }

    #endregion
  }

  public class MailAttachment
  {
    private string _attachmentFilePath;

    public MailAttachment(string attachmentFilePath)
    {
      _attachmentFilePath = attachmentFilePath;
    }

    public MapiFileDesc GetMapiFileDesc()
    {
      var mapiFileDesc = new MapiFileDesc();

      mapiFileDesc.Position = -1;
      mapiFileDesc.Path = _attachmentFilePath;
      mapiFileDesc.Name = Path.GetFileName(_attachmentFilePath);

      return mapiFileDesc;
    }
  }



  public class MailRecipient
  {
    #region Constants and Fields

    public string _emailAddress;

    public string _displayName;

    public MailRecipientType _mailRecipientType = MailRecipientType.To;

    #endregion

    #region Constructors and Destructors

    public MailRecipient(string emailAddress, string displayName, MailRecipientType mailRecipientType)
    {
      this._emailAddress = emailAddress;
      this._displayName = displayName;
      this._mailRecipientType = mailRecipientType;
    }

    #endregion

    #region Methods

    public MapiRecipDesc GetMapiRecipDesc()
    {
      var recipDesc = new MapiRecipDesc();

      if (this._displayName == null)
      {
        recipDesc.Name = this._emailAddress;
      }
      else
      {
        recipDesc.Name = this._displayName;
        recipDesc.Address = this._emailAddress;
      }

      recipDesc.RecipientClass = (int)this._mailRecipientType;

      return recipDesc;
    }

    #endregion
  }

  public enum MailRecipientType
  {
    To = 1,
    CC = 2,
    BCC = 3
  } ;

  internal class Mapi32
  {
    #region Constants and Fields

    public const int MAPI_DIALOG = 0x8;

    public const int MAPI_E_AMBIGUOUS_RECIPIENT = 21;

    public const int MAPI_E_ATTACHMENT_NOT_FOUND = 11;

    public const int MAPI_E_ATTACHMENT_OPEN_FAILURE = 12;

    public const int MAPI_E_ATTACHMENT_WRITE_FAILURE = 13;

    public const int MAPI_E_BAD_RECIPTYPE = 15;

    public const int MAPI_E_BLK_TOO_SMALL = 6;

    public const int MAPI_E_DISK_FULL = 4;

    public const int MAPI_E_FAILURE = 2;

    public const int MAPI_E_INSUFFICIENT_MEMORY = 5;

    public const int MAPI_E_INVALID_EDITFIELDS = 24;

    public const int MAPI_E_INVALID_MESSAGE = 17;

    public const int MAPI_E_INVALID_PARAMETER = 998;

    public const int MAPI_E_INVALID_RECIPS = 25;

    public const int MAPI_E_INVALID_SESSION = 19;

    public const int MAPI_E_LOGIN_FAILURE = 3;

    public const int MAPI_E_MESSAGE_IN_USE = 22;

    public const int MAPI_E_NETWORK_FAILURE = 23;

    public const int MAPI_E_NOT_SUPPORTED = 26;

    public const int MAPI_E_NO_LIBRARY = 999;

    public const int MAPI_E_NO_MESSAGES = 16;

    public const int MAPI_E_TEXT_TOO_LARGE = 18;

    public const int MAPI_E_TOO_MANY_FILES = 9;

    public const int MAPI_E_TOO_MANY_RECIPIENTS = 10;

    public const int MAPI_E_TOO_MANY_SESSIONS = 8;

    public const int MAPI_E_TYPE_NOT_SUPPORTED = 20;

    public const int MAPI_E_UNKNOWN_RECIPIENT = 14;

    public const int MAPI_LOGON_UI = 0x1;

    public const int MAPI_USER_ABORT = 1;

    public const int SUCCESS_SUCCESS = 0;

    #endregion

    #region Public Methods

    [DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)]
    public static extern int MAPILogon(IntPtr hwnd, string prf, string pw, int flg, int rsv, ref IntPtr sess);

    [DllImport("MAPI32.DLL")]
    public static extern int MAPISendMail(IntPtr session, IntPtr hwnd, MapiMessage message, int flg, int rsv);

    #endregion
  }

  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  public class MapiFileDesc
  {
    public int Reserved;

    public int Flags;

    public int Position;

    public string Path;

    public string Name;

    public IntPtr Type = IntPtr.Zero;
  }

  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  public 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 = IntPtr.Zero;

    public int RecipientCount;

    public IntPtr Recipients = IntPtr.Zero;

    public int FileCount;

    public IntPtr Files = IntPtr.Zero;
  }

  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  public class MapiRecipDesc
  {
    public int Reserved;

    public int RecipientClass;

    public string Name;

    public string Address;

    public int eIDSize;

    public IntPtr EntryID = IntPtr.Zero;
  }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜