Проблемы с кодировкой при отправке email писем посредством php мы уже разобрали в предыдущей части нашей статьи. Давайте разберёмся с оставшимися вопросами.
Итак, на повестке дня: использование вложений и вставка изображения в тело письма.
Наверняка многим на почту приходили красивые письма с вёрсткой и картинками. А отправляя письма собственноручно, приходит некрасивый текст. В данной статье мы научимся отправлять письма с красивой версткой и картинками, что часто бывает необходимо при отправке рассылок.
Если вы когда-нибудь сталкивались с отправкой таких писем, то, скорее всего у вас часто возникали следующие проблемы:
- вложенный файл не открывается или открывается неправильно
- не показывается текст
- картинку можно скачать, но она не вставляется в тело письма.
Давайте, попробуем со всем этим разобраться.
Для отправки писем с вложениями используется специальный формат, который называется multipart. В заголовках (headers) он указывается как Content-type: multipart/mixed; boundary=... При этом тело письма состоит из кусочков (каждый кусочек — это часть письма, текст или вложение), которые разделяются значением boundary. Каждый кусочек имеет свои заголовки (конечно же Content-type, ну и другие).
Если кусочку ещё и задать Content-ID, то его можно вставлять в HTML (ссылка при этом будет выглядеть как «CID:<значение Content-ID>»).
Написаный ранее класс для работы с почтой я модифицировал под отправку multipart сообщений:
class TEmail{
public $from_email;
public $from_name;
public $to_email;
public $to_name;
public $subject;
public $data_charset='UTF-8';
public $send_charset='windows-1251';
//Части сообщения - текст и т.п.
private $EOL;
private $parts=array();
//Конструктор
function __construct(){
$this->EOL=CHR(13).CHR(10);
}
//Функция, прикрепляющая файл
function attachment($content_type,$name,$fn,$content_id=''){
//Read data from the file...
$fp=fopen($fn,'rb');
if(!$fp)return false;
$str=fread($fp,filesize($fn));
fclose($fp);
$msg['attachment']=true;
$msg['content_type']=$content_type;
$msg['content_id']=$content_id; //Для вставки в тело письма
$msg['data']=$str;
$msg['name']=$name;
$msg['send_charset']='';
$msg['transfer_encoding']='base64';
array_push($this->parts,$msg);
}
//Функция, добавляющая тело сообщения
function body($content_type,$str){
$msg['attachment']=false;
$msg['content_type']=$content_type;
$msg['content_id']='';
$msg['data']=$str;
$msg['name']='';
$msg['send_charset']=$this->send_charset;
$msg['transfer_encoding']='8bit';//'quoted-printable';
array_push($this->parts,$msg);
}
//Функция для отправки multipart сообщения (с вложениями)
function send_multipart(){
$dc=$this->data_charset;
$sc=$this->send_charset;
$EOL=$this->EOL;
$boundary='a'.sha1(uniqid(time()));//любая строка, которой не будет в потоке данных.
//Encode some fields
$enc_to=mime_header_encode($this->to_name,$dc,$sc).' <'.$this->to_email.'>';
$enc_subject=mime_header_encode($this->subject,$dc,$sc);
if(!empty($this->from_email))
$enc_from=mime_header_encode($this->from_name, $dc, $sc).' <'.$this->from_email.'>';else
$enc_from='';
//Process data...
$multipart='';
for($i=0;$i<count($this->parts);$i++){
$ctype=$this->parts[$i]['content_type'];
$cname=$this->parts[$i]['name'];
$ccharset=$this->parts[$i]['send_charset'];
$ctenc=$this->parts[$i]['transfer_encoding'];
$cid=$this->parts[$i]['content_id'];
//Put file into multipart
$multipart.='--'.$boundary.$EOL;
$multipart.='Content-Type: '.$ctype.
(empty($ccharset)?'':'; charset='.$ccharset).
(empty($cname)?'':'; name='.$cname).$EOL;
if(!empty($cid))
$multipart.='Content-ID: <'.$cid.'>'.$EOL;
$multipart.='Content-Transfer-Encoding: '.$ctenc.$EOL;
//Different encodings
if($ctenc=='8bit'){//quoted-printable
$enc_body=$dc==$ccharset?
$this->parts[$i]['data']:
iconv($dc,$ccharset.'//IGNORE',$this->parts[$i]['data']);
$multipart.=$EOL.$enc_body.$EOL;
}else
if($ctenc=='base64'){
$multipart.=$EOL.chunk_split(base64_encode($this->parts[$i]['data']),76,$EOL).$EOL;
};
}
$multipart.='--'.$boundary.'--'.$EOL;
//
$headers='';
$headers.='Mime-Version: 1.0'.$EOL;
$headers.='Content-type: multipart/mixed; boundary='.$boundary.$EOL;
if(!empty($enc_from))
$headers.='From: '.$enc_from.$EOL;
//Send email
return mail($enc_to,$enc_subject,$multipart,$headers);
}
//Функция для отправки обычного сообщения
function send_single(){
//Get some global variables...
$dc=$this->data_charset;
$sc=$this->send_charset;
$EOL=$this->EOL;
$body=$this->parts[0]['data'];
$ctype=$this->parts[0]['content_type'];
$ccharset=$this->parts[0]['send_charset'];
//Encode some fields
$enc_to=mime_header_encode($this->to_name,$dc,$sc).' <'.$this->to_email.'>';
$enc_subject=mime_header_encode($this->subject,$dc,$sc);
if(!empty($this->from_email))
$enc_from=mime_header_encode($this->from_name, $dc, $sc).' <'.$this->from_email.'>';else
$enc_from='';
//Encode Body
$enc_body=$dc==$ccharset?$body:iconv($dc,$ccharset.'//IGNORE',$body);
//Form headers
$headers='';
$headers.='Mime-Version: 1.0'.$EOL;
$headers.='Content-type: '.$ctype.'; charset='.$ccharset.$EOL;
if(!empty($enc_from))
$headers.='From: '.$enc_from.$EOL;
//Send email
return mail($enc_to,$enc_subject,$enc_body,$headers);
}
function send(){
if(count($this->parts)==1) return $this->send_single(); else
if(count($this->parts)>1) return $this->send_multipart(); else
return false;
}
}
Тут функция send() проверяет количество «кусочков». Если «кусочек» один, то отправляет его как текст. Ведь multipart нам не нужен, если мы отправляем только текст.
Функции attachment() и body() прикрепляют текст или вложение. Принцип их работы, я думаю, понятен.
Отправка писем с вложениями не представляет сложности. Тут я прикрепляю картинку и zip-архив:
require_once(dirname(__FILE__).'/email_api.php');
echo('Trying to send emails...<br>');
//HTML email
echo('Email with attachment - sending...<br>');
$email=new TEmail;
$email->from_email='noreply@konservs.com';
$email->from_name='От "Записок Консерваторов"';
$email->to_email='*********';
$email->subject='Тема (ІЇҐЭЄ іїґэє)';
$email->body('text/html','Письмо в HTML с вложениями.<br>'.
'Картинка:'.
'<img src="cid:cid1">'.
'<h1>Header 1 (Заголовок 1)</h1>'.
'<h2>Header 2 (Заголовок 2)</h2>'.
'<h3>Header 3 (Заголовок 3)</h3>'.
'<h4>Header 4 (Заголовок 4)</h4>'.
'<h5>Header 5 (Заголовок 5)</h5>'.
'Тест: ІЇҐЭЄ іїґэє');
$DS=DIRECTORY_SEPARATOR;
$email->attachment('image/jpeg','logo.jpg',dirname(__FILE__).$DS.'files'.$DS.'test.jpg','cid1');
$email->attachment('application/octet-stream','test.zip',dirname(__FILE__).$DS.'files'.$DS.'test.zip');
if($email->send())
echo('Email with attachment - OK.<br>'); else
echo('Email with attachment - Error!<br>');
Пример письма, которое пришло мне.

Поздравляем! Вы научились отправлять письма с вложениями.
Комментарии
Спасибі!
Adding comments is temporarily disabled for unregistered users.