解决drupal8下面email 样式发送的问题, 以发送原始邮件(how to send raw email in dupal8 without any style and tag filter)
admin 提交于 星期三, 07/28/2021 - 09:42
# 解决drupal8下面email 样式发送的问题, 以发送原始邮件(how to send raw email in dupal8 without any style and tag filter)
我终于搞定了。 太不容易了, 用xdebug查了好久,才debug出来。
## 问题(problem): 最近发现时间轴的总是有样式问题, drupal默认对模板作了两次处理。 同样一个模板的, 我用nodejs来发就正常, 用drupal来发, 样式就出问题。 drupal默认对原始邮件的模板的样式和标签进行了过滤
##问题分析(root cause):
1. drupal内核代码进行了过滤(drupal core code have do some filter).
以下是处理逻辑代码的位置, Html::transformRootRelativeUrlsToAbsolute会把数据转成dom对象, 再输出, 这中间会把样式和特殊的标签给去掉。
/pathtodrupal/core/lib/Drupal/Core/Mail/MailManager.php
line number 278:
```
// Retrieve the responsible implementation for this message.
$system = $this->getInstance(['module' => $module, 'key' => $key]);
// Attempt to convert relative URLs to absolute.
foreach ($message['body'] as &$body_part) {
if ($body_part instanceof MarkupInterface) {
$body_part = Markup::create(Html::transformRootRelativeUrlsToAbsolute((string) $body_part, \Drupal::request()->getSchemeAndHttpHost()));
}
}
// Format the message body.
$message = $system->format($message);
```
/pathtodrupal/core/lib/Drupal/Component/Utility/Html.php
```
public static function transformRootRelativeUrlsToAbsolute($html, $scheme_and_host) {
assert(empty(array_diff(array_keys(parse_url($scheme_and_host)), ["scheme", "host", "port"])), '$scheme_and_host contains scheme, host and port at most.');
assert(isset(parse_url($scheme_and_host)["scheme"]), '$scheme_and_host is absolute and hence has a scheme.');
assert(isset(parse_url($scheme_and_host)["host"]), '$base_url is absolute and hence has a host.');
$html_dom = Html::load($html);
$xpath = new \DOMXpath($html_dom);
...
return Html::serialize($html_dom);
}
}
```
2. drupal formater have also filter the tag.
在我的应用中, 我用了swiftmail formater, 它也去掉了特殊标签和样式。
/pathtodrupal/modules/contrib/swiftmailer/src/Plugin/Mail/SwiftMailer.php
## 如何解决(how to solve)
1. 保证传给发邮件函数的body为string, 而不是markup对象(passing string instead of markup object)
···
function mymodule_sendmail($to, $subject, $body, $params = []) {
$from = \Drupal::config('system.site')->get('mail');
$params['subject'] = $subject;
$params['body'] = $body;
$langcode = \Drupal::languageManager()->getDefaultLanguage();
// Send email with drupal_mail.
return \Drupal::service('plugin.manager.mail')->mail('wristcheck_mail', 'wristcheck_mail', $to, $langcode, $params, $from);
}
···
保证body为string, 而不是markup对象
2. 自己写一个不对邮件过滤的formater(write a self formater)
最后, 是自己写了一个emal formater, 替代了内置的formater了, 不做处理, 这样才解决。
/pathtodrupal/modules/custom/mymodule/src/Plugin/Mail/MymoduleMailer.php
```
<?php
namespace Drupal\wristcheck_mail\Plugin\Mail;
use Drupal\Core\Mail\MailInterface;
/**
* Provides a 'Mymodule Mailer' plugin to send emails.
*
* @Mail(
* id = "mymodulemailer",
* label = @Translation("Mymodule Mailer"),
* description = @Translation("Mymodule Mailer Plugin.")
* )
*/
class MymoduleMailer implements MailInterface {
/**
* Formats a message composed by drupal_mail().
*
* @param array $message
* A message array holding all relevant details for the message.
*
* @return array
* The message as it should be sent.
*/
public function format(array $message) {
$text = '';
foreach ($message['body'] as $body) {
$text = $text . $body;
}
$message['body'] = $text;
return $message;
}
/**
* Sends a message composed by drupal_mail().
*
* @param array $message
* A message array holding all relevant details for the message.
*
* @return bool
* TRUE if the message was successfully sent, and otherwise FALSE.
*/
public function mail(array $message) {
return FALSE;
}
}
```