Ниже описана последовательность действий для отправки почты со своего сервера с помощью PHPMailer + DKIM
Последовательность действий:
- Заходим на и формируем ключ для домена
- Сохраняем их себе на компьютер или добавляем урл в избранное
- Заходим в настройки домена и добавляем DKIM TXT запись к домену
- Заходим снова в настройки домена и добавляем SPF TXT запись к домену
- Скачиваем последнюю версию
- Вносим изменения в PHPmailer и отправляем письма уже с DKIM подписью
Редактируем файл class.phpmailer.php
К сожалению в последней версии он не совсем корректно формирует подпись, поэтому пришлось внести некоторые правки
public function preSend()
{
try {
$this->DKIM_domain = "google.com";
$this->DKIM_selector = "1426607473.google";
$this->DKIM_private = JPATH_SITE . DS . 'libraries' . DS . 'phpmailer' . DS . 'dkim_private.key';
$this->mailHeader = '';
if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL);
}
// Set whether the message is multipart/alternative
if (!empty($this->AltBody)) {
$this->ContentType = 'multipart/alternative';
}
$this->error_count = 0; // reset errors
$this->setMessageType();
// Refuse to send an empty message unless we are specifically allowing it
if (!$this->AllowEmpty and empty($this->Body)) {
throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL);
}
$this->MIMEHeader = $this->createHeader();
$this->MIMEBody = $this->createBody();
// To capture the complete message when using mail(), create
// an extra header list which createHeader() doesn't fold in
if ($this->Mailer == 'mail') {
if (count($this->to) > 0) {
$this->mailHeader .= $this->addrAppend('To', $this->to);
} else {
$this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;');
}
$this->mailHeader .= $this->headerLine(
'Subject',
$this->encodeHeader($this->secureHeader(trim($this->Subject)))
);
}
// digitally sign with DKIM if enabled
if (!empty($this->DKIM_domain) && !empty($this->DKIM_private) && !empty($this->DKIM_selector)) {
$header_dkim = $this->ACY_DKIM_Add($this->MIMEBody);
$this->MIMEHeader = str_replace("\r\n", "\n", $header_dkim) . $this->MIMEHeader;
}
if (!empty($this->DKIM_domain)
&& !empty($this->DKIM_private)
&& !empty($this->DKIM_selector)
&& file_exists($this->DKIM_private)) {
/*
$header_dkim = $this->DKIM_Add(
$this->MIMEHeader . $this->mailHeader,
$this->encodeHeader($this->secureHeader($this->Subject)),
$this->MIMEBody
);
$this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF .
str_replace("\r\n", "\n", $header_dkim) . self::CRLF;
*/
$this->DKIM_private = file_get_contents($this->DKIM_private);
$header_dkim = $this->ACY_DKIM_Add($this->MIMEBody);
$this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF . str_replace("\r\n", "\n", $header_dkim) . self::CRLF;
}
return true;
} catch (phpmailerException $exc) {
$this->setError($exc->getMessage());
if ($this->exceptions) {
throw $exc;
}
return false;
}
}
А вот так выглядит dkim_private.key:
-----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQDDG9axtmNQ18 ...... XCWmtRywbPmnqH2RNBTQSf -----END RSA PRIVATE KEY-----
Добавляете две функции ACY_DKIM_Add и ACY_DKIM_Sign ничего не меняя в них
protected function ACY_DKIM_Add($body) {
$DKIMsignatureType = 'rsa-sha1'; // Signature & hash algorithms
$DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body
$DKIMquery = 'dns/txt'; // Query method
$DKIMtime = time() ; // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone)
$subject = $this->EncodeHeader($this->SecureHeader($this->Subject));
$subjecta_header = "Subject: $subject";
$from = array();
$from[0][0] = trim($this->From);
$from[0][1] = $this->FromName;
$fromc_header = $this->AddrAppend('From', $from);
$toy_header = $this->AddrAppend('To', $this->to);
$body = $this->DKIM_BodyC($body);
$DKIMlen = strlen($body) ; // Length of body
$DKIMb64 = base64_encode(pack("H*", sha1($body))) ; // Base64 of packed binary SHA-1 hash of body
$ident = (empty($this->DKIM_identity))? '' : " i=" . $this->DKIM_identity . ";";
$dkimhdrs = "DKIM-Signature: v=1; a=" . $DKIMsignatureType . "; q=" . $DKIMquery . "; l=" . $DKIMlen . "; s=" . $this->DKIM_selector . ";\r\n".
"\tt=" . $DKIMtime . "; c=" . $DKIMcanonicalization . "; h=from:to:subject;\r\n".
"\td=" . $this->DKIM_domain . ";" . $ident ." bh=" . $DKIMb64 . ";\r\n".
"\tb=";
$toSign = $this->DKIM_HeaderC($fromc_header . "\r\n" . $toy_header . "\r\n" . $subjecta_header . "\r\n" . $dkimhdrs);
$signed = wordwrap($this->ACY_DKIM_Sign($toSign),60,"\r\n\t",true);
if(empty($signed)) return '';
return $dkimhdrs.$signed."\r\n";
}
protected function ACY_DKIM_Sign($s) {
if (!empty($this->DKIM_passphrase)) {
$privKey = openssl_pkey_get_private($this->DKIM_private,$this->DKIM_passphrase);
} else {
$privKey = $this->DKIM_private;
}
$signature = '';
if (openssl_sign($s, $signature, $privKey)) {
return base64_encode($signature);
}
}
Пример DKIM И SPF записей в домене:
| Имя записи | Тип | Контент | TTL | Приоритет |
|---|---|---|---|---|
| 1426607473. google._domainkey.google.com |
TXT | v=DKIM1;t=s;p=MIGfMA0GC....AQAB | 3600 | |
| google.com | TXT | v=spf1 a mx ip4:91.160.1.10 ~all | 3600 |
v=spf1 a mx ip4:91.160.1.10 ~all - Тут только указываете свой ip smtp сервера
Все , теперь должно все работать. Ниже можете посмотреть принскрины, а также скачать полностью архив для более детального изучения.
2015-04-29 Важный апдейт, текст сообщения обязательно оборачиваейте функцией wordwrap, иначе если у вас длинный текст, то DKIM подпись будет не верна. Пример -> wordwrap($message)
https://gaalferov.com/blog/nastrojka-dkim-spf-phpmailer.html#sigProGalleria8ead6cb868
- DKIM1 - метод E-mail аутентификации (DomainKeys Identified Mail)
- SPF2 - расширение для протокола отправки электронной почты через SMTP. SPF определен в RFC 7208.Благодаря SPF можно проверить, не подделан ли домен отправителя. (Sender Policy Framework)
