【问题标题】:VB.Net Simple MAPI email is HTML possible?VB.Net 简单的 MAPI 电子邮件是 HTML 可能的吗?
【发布时间】:2021-12-08 01:56:44
【问题描述】:

根据我的阅读,这是不可能的,但我还是在问,因为也许我错过了另一种选择......

VB.Net Windows 窗体应用程序。

此应用程序有时需要发送电子邮件,这些电子邮件是在用户邮件客户端中创建的,然后他们可以对其进行编辑和发送。这不会自动发送;它必须由用户手动发送。

我们决定使用 MAPI,因为这样可以使其与各种电子邮件客户端兼容,而不是强制使用某种形式的 Outlook;不是每个人都是 MS 的粉丝!

此代码运行良好,但问题是我需要在电子邮件中发送一个 URL,该 URL 被分成两行并且不能立即“可点击”。

我希望喜欢能够以 HTML 格式发送它,但 MAPI 似乎不支持它。

我们已经避免使用 SMTP 客户端,因为这是用户需要设置的少一件事;使用 MAPI,它利用了 IT 部门已经建立的现有电子邮件帐户以及他们可能不想向用户透露的详细信息。

那么,有没有一种方法可以创建不使用 SMTP 客户端以 HTML 格式发送电子邮件并且不花费一臂之力(又名 aspose :-))的电子邮件?


    Public Function sendMAPI(emailAddy As String, subj As String, body As String, Optional attachement As String = "") As Boolean


        Dim mapi As New SendFileTo.MAPI
        'Dim emailAddy As String = getFundingEmail(cmbFundedBy.Text)
        mapi.AddRecipientTo(emailAddy) 
        If attachement = "" Then

        Else
            mapi.AddAttachment(attachement)
        End If
        Dim q = mapi.SendMailPopup(subj, body)
        If mapi.GetLastError.Contains("OK") Then

            If Not UpdateUserLog(Now(), sUsername, "eMail to " + emailAddy + " created in MAPI client") Then
                MessageBox.Show("Unable to update user log")
            End If
            Return True
        Else
            If Not UpdateUserLog(Now(), sUsername, "eMail to " + emailAddy + " *NOT* created in MAPI client") Then
                MessageBox.Show("Unable to update user log")
            End If
            Return False
        End If
    End Function

Imports System
Imports System.Runtime.InteropServices
Imports System.IO
Imports System.Collections.Generic
Imports System.Windows.Forms

Namespace SendFileTo
    Class MAPI
        Public Function AddRecipientTo(ByVal email As String) As Boolean
            Return AddRecipient(email, howTo.MAPI_TO)
        End Function

        Public Function AddRecipientCC(ByVal email As String) As Boolean
            Return AddRecipient(email, howTo.MAPI_TO)
        End Function

        Public Function AddRecipientBCC(ByVal email As String) As Boolean
            Return AddRecipient(email, howTo.MAPI_TO)
        End Function

        Public Sub AddAttachment(ByVal strAttachmentFileName As String)
            m_attachments.Add(strAttachmentFileName)
        End Sub

        Public Function SendMailPopup(ByVal strSubject As String, ByVal strBody As String) As Integer
            Return SendMail(strSubject, strBody, MAPI_LOGON_UI Or MAPI_DIALOG)
        End Function

        Public Function SendMailDirect(ByVal strSubject As String, ByVal strBody As String) As Integer
            Return SendMail(strSubject, strBody, MAPI_LOGON_UI)
        End Function


        <DllImport("MAPI32.DLL")>
        Private Shared Function MAPISendMail(ByVal sess As IntPtr, ByVal hwnd As IntPtr, ByVal message As MapiMessage, ByVal flg As Integer, ByVal rsv As Integer) As Integer
        End Function

        Private Function SendMail(ByVal strSubject As String, ByVal strBody As String, ByVal how As Integer) As Integer
            Dim msg As MapiMessage = New MapiMessage()

            msg.subject = strSubject
            msg.noteText = strBody

            msg.recips = GetRecipients(msg.recipCount)
            msg.files = GetAttachments(msg.fileCount)

            m_lastError = MAPISendMail(New IntPtr(0), New IntPtr(0), msg, how, 0)
            If m_lastError > 1 Then
                MessageBox.Show("MAPISendMail failed! " + GetLastError(), "MAPISendMail")
            End If

            Cleanup(msg)
            Return m_lastError
        End Function

        Private Function AddRecipient(ByVal email As String, ByVal howTo As howTo) As Boolean
            Dim recipient As MapiRecipDesc = New MapiRecipDesc()

            recipient.recipClass = CType(howTo, Integer)
            recipient.name = email
            m_recipients.Add(recipient)

            Return True
        End Function

        Private Function GetRecipients(ByRef recipCount As Integer) As IntPtr
            recipCount = 0
            If m_recipients.Count = 0 Then
                Return 0
            End If

            Dim size As Integer = Marshal.SizeOf(GetType(MapiRecipDesc))
            Dim intPtr As IntPtr = Marshal.AllocHGlobal(m_recipients.Count * size)

            Dim ptr As Integer = CType(intPtr, Integer)
            Dim mapiDesc As MapiRecipDesc
            For Each mapiDesc In m_recipients
                Marshal.StructureToPtr(mapiDesc, CType(ptr, IntPtr), False)
                ptr += size
            Next

            recipCount = m_recipients.Count
            Return intPtr
        End Function

        Private Function GetAttachments(ByRef fileCount As Integer) As IntPtr
            fileCount = 0
            If m_attachments Is Nothing Then
                Return 0
            End If

            If (m_attachments.Count <= 0) Or (m_attachments.Count > maxAttachments) Then
                Return 0
            End If

            Dim size As Integer = Marshal.SizeOf(GetType(MapiFileDesc))
            Dim intPtr As IntPtr = Marshal.AllocHGlobal(m_attachments.Count * size)

            Dim mapiFileDesc As MapiFileDesc = New MapiFileDesc()
            mapiFileDesc.position = -1
            Dim ptr As Integer = CType(intPtr, Integer)

            Dim strAttachment As String
            For Each strAttachment In m_attachments
                mapiFileDesc.name = Path.GetFileName(strAttachment)
                mapiFileDesc.path = strAttachment
                Marshal.StructureToPtr(mapiFileDesc, CType(ptr, IntPtr), False)
                ptr += size
            Next

            fileCount = m_attachments.Count
            Return intPtr
        End Function

        Private Sub Cleanup(ByRef msg As MapiMessage)
            Dim size As Integer = Marshal.SizeOf(GetType(MapiRecipDesc))
            Dim ptr As Integer = 0

            If msg.recips <> IntPtr.Zero Then
                ptr = CType(msg.recips, Integer)
                Dim i As Integer
                For i = 0 To msg.recipCount - 1 Step i + 1
                    Marshal.DestroyStructure(CType(ptr, IntPtr), GetType(MapiRecipDesc))
                    ptr += size
                Next
                Marshal.FreeHGlobal(msg.recips)
            End If

            If msg.files <> IntPtr.Zero Then
                size = Marshal.SizeOf(GetType(MapiFileDesc))

                ptr = CType(msg.files, Integer)
                Dim i As Integer
                For i = 0 To msg.fileCount - 1 Step i + 1
                    Marshal.DestroyStructure(CType(ptr, IntPtr), GetType(MapiFileDesc))
                    ptr += size
                Next
                Marshal.FreeHGlobal(msg.files)
            End If

            m_recipients.Clear()
            m_attachments.Clear()
            m_lastError = 0
        End Sub

        Public Function GetLastError() As String
            If m_lastError <= 26 Then
                Return errors(m_lastError)
            End If
            Return "MAPI error [" + m_lastError.ToString() + "]"
        End Function

        ReadOnly errors() As String = 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]"}

        Dim m_recipients As New List(Of MapiRecipDesc)
        Dim m_attachments As New List(Of String)
        Dim m_lastError As Integer = 0

        Private Const MAPI_LOGON_UI As Integer = &H1
        Private Const MAPI_DIALOG As Integer = &H8
        Private Const maxAttachments As Integer = 20

        Enum howTo
            MAPI_ORIG = 0
            MAPI_TO
            MAPI_CC
            MAPI_BCC
        End Enum

    End Class

    <StructLayout(LayoutKind.Sequential)>
    Public Class MapiMessage
        Public reserved As Integer
        Public subject As String
        Public noteText As String
        Public messageType As String
        Public dateReceived As String
        Public conversationID As String
        Public flags As Integer
        Public originator As IntPtr
        Public recipCount As Integer
        Public recips As IntPtr
        Public fileCount As Integer
        Public files As IntPtr
    End Class

    <StructLayout(LayoutKind.Sequential)>
    Public Class MapiFileDesc
        Public reserved As Integer
        Public flags As Integer
        Public position As Integer
        Public path As String
        Public name As String
        Public type As IntPtr
    End Class

    <StructLayout(LayoutKind.Sequential)>
    Public Class MapiRecipDesc
        Public reserved As Integer
        Public recipClass As Integer
        Public name As String
        Public address As String
        Public eIDSize As Integer
        Public enTryID As IntPtr
    End Class
End Namespace

【问题讨论】:

  • 首先,这是Simple MAPI,不支持HTML。
  • 谢谢德米特里。我一直在努力寻找其他有效的方法!你有什么别的推荐吗?
  • 在 Outlook 版本的 Simple MAPI 中曾经有一个错误,它允许传递 HTML 而不是纯文本,但我认为它不再起作用了。如果安装了 Outlook,OOM 将工作。如果没有,您可以回退到 Simple MAPI。
  • 如你所说,我已经在使用简单的 MAPI。我需要发送 HTML 电子邮件
  • 可以在调用MailItem.Send之前使用OOM并设置MailItem.HTMLBody属性。

标签: vb.net email mapi simple-mapi


【解决方案1】:

使用 Simple MAPI (MAPISendMailW) 时有一个技巧 - 您需要将正文设置为 NULL 并附加一个 HTML 文件。此文件将用作消息正文!

【讨论】:

  • 我认为这不适用于最新版本的 Outlook,也不适用于其他电子邮件客户端。
  • 使用 Outlook 365 似乎可以工作!需要更多测试;-)
  • 它似乎不适用于 Pegasus,但这可能是安装错误。我认为我们现在有一些可以使用的东西 - 谢谢尤金
  • 非常感谢它的魅力
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-19
相关资源
最近更新 更多