使用 SmtpClient 发送邮件时图像损坏

问题描述 投票:0回答:3

我正在使用 C# 使用

SmtpClient
类发送邮件。在发送邮件之前我正在做以下事情。

var mailMessage = new MailMessage();

model.ToAddresses.ForEach(to => mailMessage.To.Add(to));
mailMessage.Subject = "Test Email - By Yasser";

mailMessage.Body = String.Format("{0}{1}{2}",
                                    "<html><body>",
                                     GetEmailContent(model),
                                     "</body></html>");
mailMessage.IsBodyHtml = true;
return MailService.SendEmail(mailMessage);

下面是我的 MailService 类:

public class MailService
{
    public static bool SendEmail(MailMessage mailMessage)
    {
        var smtpClient = new SmtpClient();
        try
        {
            smtpClient.Send(mailMessage);
            return true;
        }
        catch(Exception exp)
        {
            return false;
        }
    }
}

现在,当我发送邮件时,邮件就会被发送,这是当我按查看源时在 Outlook 中得到的邮件内容。下面是带查看源码的邮件内容(显然我只保留了一部分图片数据)

<html>

<body>
    <h1>Test</h1>
    <h2>Hello World</h2>
    <h3>Missing close h3 tag</h3>

    <p>
        <a href="www.google.com">
            <img src="data:image/gif;base64,/9j/4AAQSkZJRgABAgEAYABgAAD/4Q8HRXhpZgAAT" />
        </a>
    </p>
</body>

</html>

因此,这在邮件中显得损坏(图像),但是当我复制此源代码并将其粘贴到编辑器中并使用浏览器打开文件时,一切似乎都很好(甚至是图像)。

更新:添加了 Outlook 邮件的图像

enter image description here

有什么想法吗????

c# html email smtpclient
3个回答
16
投票

这是我尝试过并且对我有用的方法,在 Outlook、Thunderbird 和 Gmail 中进行了测试。工作正常!

您可能需要查看我提到的以下资源以实现此目的:

示例代码:

// we need to use the prefix 'cid' in the img src value
string emailReadyHtml = string.empty;
emailReadyHtml += "<p>Hello World, below are two embedded images : </p>";
emailReadyHtml += "<img src=\"cid:yasser\" >";
emailReadyHtml += "<img src=\"cid:smile\" >";

MailMessage mailMessage = new MailMessage();

mailMessage.To.Add("[email protected]");
mailMessage.From = new MailAddress("[email protected]", "Info");

mailMessage.Subject = "Test Mail";
mailMessage.IsBodyHtml = true;

string image1Path = HttpContext.Current.Server.MapPath("~/Content/images/yasser.jpg");
byte[] image2Bytes = someArrayOfByte;

ContentType c = new ContentType("image/jpeg");

// create image resource from image path using LinkedResource class.
LinkedResource linkedResource1 = new LinkedResource(imagePath);
linkedResource1.ContentType = c ;
linkedResource1.ContentId = "yasser";
linkedResource1.TransferEncoding = TransferEncoding.Base64;

// the linked resource can be created from bytes also, which may be stored in database (which was my case)
LinkedResource linkedResource2 = new LinkedResource(new MemoryStream(image2Bytes));
linkedResource2.ContentType = c;
linkedResource2.ContentId = "smile";
linkedResource2.TransferEncoding = TransferEncoding.Base64;

AlternateView alternativeView = AlternateView.CreateAlternateViewFromString(emailReadyHtml, null, MediaTypeNames.Text.Html);

alternativeView.ContentId = "htmlView";
alternativeView.TransferEncoding = TransferEncoding.SevenBit;

alternativeView.LinkedResources.Add(linkedResource1) ;
alternativeView.LinkedResources.Add(linkedResource2);

mailMessage.AlternateViews.Add(alternativeView);

SmtpClient smtpClient = new SmtpClient();
smtpClient.Send(mailMessage);

3
投票

这是一个可以解决这个问题的函数。在 SendEmail 之前调用它,例如:

ProcessEmbeddingImages(mailMessage);
return MailService.SendEmail(mailMessage);

ProcessEmbeddingImages 函数是用 VB.Net 编写的,因此您可能需要使用这些在线翻译器之一将其翻译为 C#。

Private Sub ProcessEmbeddingImages(ByRef oMail As System.Net.Mail.MailMessage)
    Dim oLinkedResources As New Hashtable()
    oMail.Body = PadSrcDataImage(oMail.Body, oLinkedResources)
    If oLinkedResources.Count > 0 Then

        Dim oAlternateView As System.Net.Mail.AlternateView = System.Net.Mail.AlternateView.CreateAlternateViewFromString(oMail.Body, Nothing, "text/html")
        oAlternateView.ContentId = "htmlView"
        oAlternateView.TransferEncoding = Net.Mime.TransferEncoding.SevenBit

        For Each oItem As DictionaryEntry In oLinkedResources
            Dim oKey As String() = Split(oItem.Key, "-")
            Dim i As Integer = oKey(0)
            Dim sExt As String = oKey(1)
            Dim sData As String = oItem.Value

            Dim oLinkedResource As New System.Net.Mail.LinkedResource(New IO.MemoryStream(System.Convert.FromBase64String(sData)))
            oLinkedResource.ContentId = "MyImg" & i
            oLinkedResource.TransferEncoding = Net.Mime.TransferEncoding.Base64
            oLinkedResource.ContentType = New System.Net.Mime.ContentType("image/" & sExt)
            oAlternateView.LinkedResources.Add(oLinkedResource)
        Next

        oMail.AlternateViews.Add(oAlternateView)
    End If
End Sub

Private Function PadSrcDataImage(ByVal sHtml As String, ByRef oLinkedResources As Hashtable) As String

    Dim oList As New ArrayList
    Dim sSearch As String = "\ssrc=['""]data:image/(.*?);base64,(.*?)['""]"

    Dim oMatches As System.Text.RegularExpressions.MatchCollection = System.Text.RegularExpressions.Regex.Matches(sHtml, sSearch, System.Text.RegularExpressions.RegexOptions.IgnoreCase)
    For Each m As System.Text.RegularExpressions.Match In oMatches
        If m.Groups.Count >= 2 Then
            Dim sExt As String = m.Groups(1).Value
            Dim sData As String = m.Groups(2).Value

            If sData.Length > 7 AndAlso Right(sData, 6) = "%3D%3D" Then
                'Replace trailing %3D%3D with ==
                sData = Left(sData, sData.Length - 6) & "=="
            End If

            oLinkedResources.Add(oLinkedResources.Count & "-" & sExt, sData)

            Dim iPos1 As Integer = m.Groups(1).Index - "data:image/".Length
            Dim iPos2 As Integer = m.Groups(2).Index + m.Groups(2).Length
            Dim iPoints As Integer() = {iPos1, iPos2}
            oList.Add(iPoints)
        End If
    Next

    Dim sRet As String = ""

    If oList.Count = 1 Then 'One img
        Dim iPoints As Integer() = oList(0)
        Dim sStr1 As String = sHtml.Substring(0, iPoints(0))
        Dim sStr2 As String = sHtml.Substring(iPoints(1))
        sRet = sStr1 & "cid:MyImg0" & sStr2

    ElseIf oList.Count > 1 Then

        For i As Integer = 0 To oList.Count - 1
            Dim iPoints As Integer() = oList(i)
            Dim iPos1 As Integer = iPoints(0)

            If i = 0 Then
                'First img
                Dim sStr1 As String = sHtml.Substring(0, iPos1)
                sRet += sStr1 & "cid:MyImg" & i

            Else 'Rest imgs
                Dim iPrevPos2 As Integer = oList(i - 1)(1)
                Dim sStr1 As String = sHtml.Substring(iPrevPos2, iPos1 - iPrevPos2)
                sRet += sStr1 & "cid:MyImg" & i

                If i = oList.Count - 1 Then    'Last
                    sRet += sHtml.Substring(iPoints(1))
                End If
            End If
        Next
    End If

    If sRet <> "" Then
        Return sRet
    Else
        Return sHtml
    End If
End Function

0
投票

为了配合 Igor 的 Visual Basic Response,这里介绍了 C#

   static void ProcessEmbeddingImages(ref MailMessage oMail)
    {
        Hashtable oLinkedResources = new Hashtable();
        oMail.Body = PadSrcDataImage(oMail.Body, ref oLinkedResources);
        if (oLinkedResources.Count > 0)
        {
            AlternateView oAlternateView = AlternateView.CreateAlternateViewFromString(oMail.Body, null, "text/html");
            oAlternateView.ContentId = "htmlView";
            oAlternateView.TransferEncoding = System.Net.Mime.TransferEncoding.SevenBit;

            foreach (DictionaryEntry oItem in oLinkedResources)
            {
                string[] oKey = ((string)oItem.Key).Split('-');
                int i = int.Parse(oKey[0]);
                string sExt = oKey[1];
                string sData = (string)oItem.Value;

                LinkedResource oLinkedResource = new LinkedResource(new System.IO.MemoryStream(Convert.FromBase64String(sData)));
                oLinkedResource.ContentId = "MyImg" + i;
                oLinkedResource.TransferEncoding = System.Net.Mime.TransferEncoding.Base64;
                oLinkedResource.ContentType = new System.Net.Mime.ContentType("image/" + sExt);
                oAlternateView.LinkedResources.Add(oLinkedResource);
            }

            oMail.AlternateViews.Add(oAlternateView);
        }
    }

    static string PadSrcDataImage(string sHtml, ref Hashtable oLinkedResources)
    {
        ArrayList oList = new ArrayList();
        string sSearch = @"\ssrc=['""]data:image/(.*?);base64,(.*?)['""]";

        MatchCollection oMatches = Regex.Matches(sHtml, sSearch, RegexOptions.IgnoreCase);
        foreach (Match m in oMatches)
        {
            if (m.Groups.Count >= 2)
            {
                string sExt = m.Groups[1].Value;
                string sData = m.Groups[2].Value;

                if (sData.Length > 7 && sData.EndsWith("%3D%3D"))
                {
                    // Replace trailing %3D%3D with ==
                    sData = sData.Substring(0, sData.Length - 6) + "==";
                }

                oLinkedResources.Add(oLinkedResources.Count + "-" + sExt, sData);

                int iPos1 = m.Groups[1].Index - "data:image/".Length;
                int iPos2 = m.Groups[2].Index + m.Groups[2].Length;
                int[] iPoints = { iPos1, iPos2 };
                oList.Add(iPoints);
            }
        }

        string sRet = "";

        if (oList.Count == 1) // One img
        {
            int[] iPoints = (int[])oList[0];
            string sStr1 = sHtml.Substring(0, iPoints[0]);
            string sStr2 = sHtml.Substring(iPoints[1]);
            sRet = sStr1 + "cid:MyImg0" + sStr2;
        }
        else if (oList.Count > 1)
        {
            for (int i = 0; i < oList.Count; i++)
            {
                int[] iPoints = (int[])oList[i];
                int iPos1 = iPoints[0];

                if (i == 0)
                {
                    // First img
                    string sStr1 = sHtml.Substring(0, iPos1);
                    sRet += sStr1 + "cid:MyImg" + i;
                }
                else // Rest imgs
                {
                    int iPrevPos2 = ((int[])oList[i - 1])[1];
                    string sStr1 = sHtml.Substring(iPrevPos2, iPos1 - iPrevPos2);
                    sRet += sStr1 + "cid:MyImg" + i;

                    if (i == oList.Count - 1) // Last
                    {
                        sRet += sHtml.Substring(iPoints[1]);
                    }
                }
            }
        }

        if (!string.IsNullOrEmpty(sRet))
        {
            return sRet;
        }
        else
        {
            return sHtml;
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.