Письма в html-формате с вложенными изображениями

в 10:36, , рубрики: php, метки:

Резонный вопрос: зачем аттачить изображения, ведь это утяжеляет письма и увеличивает трафик? А чтобы не было такого:

image

Данный вид возникает в случае если пользователь читает полученную корреспонденцию оффлайн или почтовый клиент не открывает картинки из внешних источников, например из-за его настроек безопасности. Короче говоря, выглядит это может быть и читабельно, но не эстетично.

Если приаттачить картинки к письму, то оно обретёт целостный вид, и дырок уже не будет, если не допущено ошибок на этапе вёрстки.

Итак, необходимо получить возможность создавать полноценные html-шаблоны писем с картинками для их дальнейшего использования в программе (рассылка, автоматические уведомления и т.п.). В последующем шаблоны сможет готовить человек, занимающийся только версткой, без вмешательства в код программы.

Задача типичная, можно сказать обыденная, и реализаций уже придумано не мало. И чтобы не порождать 100500-й веолосипед, обратимся к небезызвестному Swift Mailer, немного расширив его функциональность применительно к нашей задаче.

Так будет выглядеть условный шаблон письма, назовём его index.html:

<html><head></head><body>
<img src=”images/company_logo.gif” >
Здравствуйте, {username}! Сообщаем Вам, что если сегодня вы навестите наш сайт, то сможете получить {something} абсолютно безвозмездно, то есть даром. 
<div>Фото подарка: <img src=”images/{something_photo}”></div>
</body></html>

Структура каталогов для хранения шаблонов может выглядеть таким образом:

email_templates/
	template1/
		index.html
		images/
			company_logo.gif
			photo1.png
			...
			photoN.png
	template2/
	...

Класс:

class SendEMail
{
	static $transport = false;

	public $filename = 'index.html',
		   // путь к html шаблону
		   $tplFolder = '',
		   // каталог с картинками
		   $imgFolder = 'images/',
		   $subject = '',
		   $from = '',
		   $fromName = null,
		   $contentType = 'text/html',
		   $charset = 'utf-8';

	private $message, $data;

	public function __construct($options)
	{
		foreach($options as $option => $value)
			$this->$option = $value;
		if (!self::$transport)
			self::$transport = Swift_SmtpTransport::newInstance();
	}

	public function Send($data, $email, $name = null)
	{
		$this->data = $data;
		$this->message = Swift_Message::newInstance();
		$mess =& $this->message;
		
		// подставляем данные в subject письма, если там есть соответствующие теги
		$subject = $this->SubstituteData($this->subject);
		$body = $this->GetBody();
		
		// email и имя получателя
		$mess->setTo($email, $name);
		// от кого
		$mess->setFrom($this->from, $this->fromName);
		// тема письма
		$mess->setSubject($subject);
		// сообщение
		$mess->setBody($body);
		$mess->setContentType($this->contentType);
		$mess->setCharset($this->charset);
		
		$mailer = Swift_Mailer::newInstance(self::$transport);
		return $mailer->send($this->message);
	}

	private function GetBody()
	{
		// считываем шаблон письма
		$body = file_get_contents($this->tplPath.$this->filename);
		// подставляем данные в шаблон
		$body = $this->SubstituteData($body);
		// аттачим все картинки, с подходящими imgPath и расширениями jpg, png, gif, заменяем атрибуты src в тегах img
		// 'self::AddImage' будет работать для php > 5.3, для 5.2 нужно заменить на array($this, 'AddImage')
		return preg_replace_callback('/'.preg_quote($this->imgPath, '/').'((.+).(jpg|png|gif))/i', 'self::AddImage', $body);
	}

	// прикрепляем картинку, меняем src
	private function AddImage($matches)
	{
		$path = $this->tplPath."/".$matches[0];
		return $this->message->embed(Swift_Image::fromPath($path));
	}

	// заменяем теги на соответствующие данные
	private function SubstituteData($str)
	{
		if (empty($this->data))
			return $str;
		foreach($this->data as $k => $v)
			$str = str_replace($k, $v, $str);
		return $str;
	}
}

Пример рассылки:

$sm = new SendEMail(array(
	'tplPath'  => '/path_to_emails/email_templates/template1/',
	'subject' => 'Чудесные подарки',
	'from'    => 'noreply@site.com'
));

$recipients[0] = array(
	'email'           => 'dima@blabla.com',
	'user'            => 'Дмитрий Владимирович',
	'something'       => 'Мялка',
	'something_photo' => 'myalka.jpg'
);
$recipients[1] = array(
	'email'           => 'volodya@blabla.com',
	'user'            => 'Владимир Анатольевич',
	'something'       => 'Мешалка',
	'something_photo' => 'meshalka.jpg'
);
$success = 0;
foreach($recipients as $rec) {
	$data = array('{user}' => $rec['user'], '{something}' => $rec['something'], '{something_photo}' => $rec['something_photo']);
	$sended = $sm->Send($data, $rec['email'], $rec['user']);
	if ($sended)
		$success++;
}

Теперь необходимо следить за размерами создаваемых писем, и не превышать разумные объёмы, проявляя заботу о тех, у кого интернет с телефона, медленный, с оплатой по трафику.

Конечно, данные следует брать из БД, это всего лишь пример. В классе также отсутствуют обработчики ошибок для уменьшения количества строк, лучшей читаемости кода и понимания.

Автор: ekokh

Источник


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js