通过 Gmail API 发送电子邮件时应用 MSO 条件语句

Posted

技术标签:

【中文标题】通过 Gmail API 发送电子邮件时应用 MSO 条件语句【英文标题】:Apply MSO conditional statements when sending email via Gmail API 【发布时间】:2021-06-30 21:04:20 【问题描述】:

我一直在使用 php 和 SwiftMailer 从 GSuite 帐户中的多个地址发送基本和更高级的 html 电子邮件。

我一直通过 SMTP 发送这些电子邮件,并使用用户名和密码进行身份验证。这意味着我需要在所有帐户上启用 Gmail 的不太安全的应用程序 (LSA)。据我所知,这些电子邮件在任何地方都显示良好 - 包括旧版本的 Outlook。

确保 LSA 设置保持打开状态并且我们在系统中拥有最新的帐户密码,这足以成为切换到 API 方法的理由。此外,我了解到 GSuite 帐户将不会很快被允许继续使用 LSA 方法——它本来应该已经发生,但由于大流行而被推迟。 https://9to5google.com/2019/12/17/g-suite-less-secure-apps/

我在 GSuite 中设置了一个邮件服务帐户。我没有使用 Swiftmailer 进行发送,而是选择了 Gmail 'quickstart' PHP 库。这适用于基本的 HTML 格式的电子邮件。当我说基本时,我说的是标题和强标签以及用于字体颜色的一点内联 css。

下一个目标是发送更复杂的 HTML 电子邮件,其中包括更多样式、嵌入的远程图像和一些 MSO 条件语句。电子邮件正在发送和传递。当我查看电子邮件的 HTML 源代码时,MSO 条件语句与其他标签(包括特定于 MS 的 doctype 内容)一样似乎被删除了。此 HTML 与 SwiftMailer 和 SMTP 一起使用。

电子邮件在 Gmail、我的 android 电子邮件应用程序和 Thunderbird 中看起来仍然很棒。它们在我尝试过的任何 Microsoft 中看起来都不正确 - 到目前为止 Outlook 07 和 Win 10 Mail。我可能不再需要担心 Outlook 07,但如果 Win 10 邮件不起作用,我担心的是 Outlook 365,这样也不会。

如果我不能使用这些 MSO 条件语句,这可能意味着一个新的、更简单的电子邮件模板。然而,根据我所阅读的所有内容,这些条件是有效的。

以下是我一直在尝试发送的 HTML 电子邮件,但条件要么不起作用,要么被剥夺。我还包含了用于发送消息的 Google 服务代码。

我尝试了在这里找到的各种编码选项、元标记和各种条件标记。如果 Google 不使用 SMTP,它会用 API 剥离东西是没有意义的。或许关键在于将 Swiftmailer 与 API 结合使用——这是我一直试图避免的另一个兔子洞。

守则

<?php               
    require_once 'Google/google-api-php-client/vendor/autoload.php';        
    
    $fromAddress = "validaccount@gsuite.com";
    
    $user_to_impersonate = $fromAddress;
    $sender = $user_to_impersonate;
                                                            
    putenv("GOOGLE_APPLICATION_CREDENTIALS=path_to_my_gmail_service_account_json_file");
    $client = new Google_Client();
    $client->useApplicationDefaultCredentials();
    $client->setSubject($sender);
    $client->setApplicationName("Quickstart");
    $client->setScopes(["https://www.googleapis.com/auth/gmail.compose"]);
    $service = new Google_Service_Gmail($client);       
    
    $fromName = "Sender Name";
    $sender = "validaccount@gsuite.com";
    $toAddress = "me@me.com";
    $toName = "My Name";
    $replyName = "Sender Name";
    $replyAddress = "validaccount@gsuite.com";
        
    $subject = "API Test";
      
    $strBody .= '<!DOCTYPE html>';
    $strBody .= '<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">';
    $strBody .= '<head>';
    $strBody .= '<meta http-equiv="content-type" content="text/html; charset=UTF-8">
        <meta name="viewport" content="width=device-width"> <!-- Forcing initial-scale shouldn\'t be necessary -->
        <meta http-equiv="X-UA-Compatible" content="IE=edge"> <!-- Use the latest (edge) version of IE rendering engine -->
        <meta name="x-apple-disable-message-reformatting">  <!-- Disable auto-scale in ios 10 Mail entirely -->
        <meta name="format-detection" content="telephone=no,address=no,email=no,date=no,url=no"> <!-- Tell iOS not to automatically link certain text strings. -->
        <meta name="color-scheme" content="light">
        <meta name="supported-color-schemes" content="light">';     
    $strBody .= '<title></title>';  
    $strBody .= '</head>';
        
    $strBody .= "<body>";
    
    $strBody .= '<![if !mso]>  HTML meant for non-Outlook clients but it shows up everywhere  <![endif]>';
    
    $strBody .= '<![if mso]>  HTML meant for Outlook clients only but it shows up everywhere  <![endif]>';
    
    $strBody .= '<!--[if mso]><!-->  I read this might work better, but again it shows up everywhere  <!--<![endif]-->';
    
    $strBody .= '<!--[if (gte mso 9)|(IE)]> This had no affect either and shows up eveywhere <![endif]-->';
                
    $strBody .= "Everybody can see this";
    
    $strBody .= "</body></html>";
                                      
    $rawMsgStr = "From: =?utf-8?B?" . base64_encode($fromName) . "?=<$sender>\r\n";
    $rawMsgStr .= "To: =?utf-8?B?" . base64_encode($toName) . "?=<$toAddress>\r\n";
    $rawMsgStr .= "Reply-To: =?utf-8?B?" . base64_encode($replyName) . "?=<$replyAddress>\r\n";
    
    $rawMsgStr .= "Subject: =?utf-8?B?" . base64_encode($subject) . "?=\r\n";
    $rawMsgStr .= "MIME-Version: 1.0\r\n";
    //$rawMsgStr .= "Content-Language: en-US;\r\n";
    $rawMsgStr .= "Content-Type: text/html; charset=utf-8\r\n\r\r";
    //$rawMsgStr .= "Content-Transfer-Encoding: quoted-printable\r\n";
    //$rawMsgStr .= 'Content-Transfer-Encoding: base64' . "\r\n\r\n";
    //$rawMsgStr .= 'Content-Transfer-Encoding: 7bit\r\n\r\n';
    $rawMsgStr .= "$strBody\r\n";           
  
    // The message needs to be encoded in Base64URL
    $mime = rtrim(strtr(base64_encode($rawMsgStr), '+/', '-_'), '=');
    $msg = new Google_Service_Gmail_Message();
    $msg->setRaw($mime);
    //return $msg;        
    
    $service->users_messages->send($sender, $msg);        
    
    echo "Complete!";         
?>

结果源 (Outlook 2007)

<html lang="en"><head><meta http-equiv="content-type" content="text/html; charset=UTF-8">
        <meta name="viewport" content="width=device-width"> 
        <meta http-equiv="X-UA-Compatible" content="IE=edge"> 
        <meta name="x-apple-disable-message-reformatting">  
        <meta name="format-detection" content="telephone=no,address=no,email=no,date=no,url=no"> 
        <meta name="color-scheme" content="light">
        <meta name="supported-color-schemes" content="light"><title></title></head><body>  HTML meant for non-Outlook clients but it shows up everywhere    HTML meant for Outlook clients only but it shows up everywhere    I read this might work better, but again it shows up everywhere  Everybody can see this</body></html>

Gmail 中生成的 HTML(Thunderbird 非常相似)

Content-Type: multipart/alternative; boundary="000000000000dc4b5d05bf2b6835"

--000000000000dc4b5d05bf2b6835
Content-Type: text/plain; charset="UTF-8"

 HTML meant for non-Outlook clients but it shows up everywhere HTML meant
for Outlook clients only but it shows up everywhere I read this might work
better, but again it shows up everywhere Everybody can see this

--000000000000dc4b5d05bf2b6835
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable


<html lang=3D"en"><head><meta http-equiv=3D"content-type" content=3D"text/h=
tml; charset=3DUTF-8">
=09    <meta name=3D"viewport" content=3D"width=3Ddevice-width">=20
=09=09<meta http-equiv=3D"X-UA-Compatible" content=3D"IE=3Dedge">=20
=09=09<meta name=3D"x-apple-disable-message-reformatting"> =20
=09=09<meta name=3D"format-detection" content=3D"telephone=3Dno,address=3Dn=
o,email=3Dno,date=3Dno,url=3Dno">=20
=09=09<meta name=3D"color-scheme" content=3D"light">
=09=09<meta name=3D"supported-color-schemes" content=3D"light"><title></tit=
le></head><body>  HTML meant for non-Outlook clients but it shows up everyw=
here    HTML meant for Outlook clients only but it shows up everywhere    I=
 read this might work better, but again it shows up everywhere  Everybody c=
an see this</body></html>

--000000000000dc4b5d05bf2b6835--

【问题讨论】:

【参考方案1】:

好吧,我认为我最终证实了这一点。 Gmail API 正在从 HTML 电子邮件中删除 cmets,并通过删除与 MSO 相关的内容来简化 doctype 标签。这不仅仅是 MSO 条件,它是电子邮件正文中的任何 HTML 注释。所以,我想这是以下内容的重复,并且正如该线程中的 OP 最近发现的那样,这个问题并没有解决,并且可能是谷歌眼中的设计。

Why does the GMail API strip the doctype and comments from outgoing messages?

最后我设计了一个更基本的 HTML 模板,没有任何 MSO 条件来绕过限制。

【讨论】:

以上是关于通过 Gmail API 发送电子邮件时应用 MSO 条件语句的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 Gmail API 从 .net 核心控制台应用程序发送电子邮件?

通过 gmail api 发送电子邮件时在电子邮件主题中使用撇号创建问题

通过 Gmail REST API 发送的电子邮件/草稿无法在新的 Gmail 用户界面中打开

无法通过 gmail api 向多个发件人发送电子邮件

尝试使用 Google.Apis.Gmail 从 asp.net core web api 应用程序从谷歌工作区发送电子邮件时出错

通过 Gmail API 发送带有纯文本回退的 HTML 电子邮件