Отправка письма с вложением

    Проблемы с кодировкой при отправке email писем посредством php мы уже разобрали в предыдущей части нашей статьи. Давайте разберёмся с оставшимися вопросами.

    Итак, на повестке дня: использование вложений и вставка изображения в тело письма.

    Наверняка многим на почту приходили красивые письма с вёрсткой и картинками. А отправляя письма собственноручно, приходит некрасивый текст. В данной статье мы научимся отправлять письма с красивой версткой и картинками, что часто бывает необходимо при отправке рассылок.

    Если вы когда-нибудь сталкивались с отправкой таких писем, то, скорее всего у вас часто возникали следующие проблемы:

    • вложенный файл не открывается или открывается неправильно
    • не показывается текст
    • картинку можно скачать, но она не вставляется в тело письма.

    Давайте, попробуем со всем этим разобраться.

    Для отправки писем с вложениями используется специальный формат, который называется multipart. В заголовках (headers) он указывается как Content-type: multipart/mixed; boundary=... При этом тело письма состоит из кусочков (каждый кусочек — это часть письма, текст или вложение), которые разделяются значением boundary. Каждый кусочек имеет свои заголовки (конечно же Content-type, ну и другие).

    Если кусочку ещё и задать Content-ID, то его можно вставлять в HTML (ссылка при этом будет выглядеть как «CID:<значение Content-ID>»).

    Написаный ранее класс для работы с почтой я модифицировал под отправку multipart сообщений:

    1. class TEmail{
    2.   public $from_email;
    3.   public $from_name;
    4.   public $to_email;
    5.   public $to_name;
    6.   public $subject;
    7.   public $data_charset='UTF-8';
    8.   public $send_charset='windows-1251';
    9.   //Части сообщения - текст и т.п.
    10.   private $EOL;
    11.   private $parts=array();
    12.   //Конструктор
    13.   function __construct(){
    14.     $this->EOL=CHR(13).CHR(10);
    15.     }
    16.   //Функция, прикрепляющая файл
    17.   function attachment($content_type,$name,$fn,$content_id=''){
    18.     //Read data from the file...
    19.     $fp=fopen($fn,'rb');
    20.     if(!$fp)return false;
    21.     $str=fread($fp,filesize($fn));
    22.     fclose($fp);
    23.     $msg['attachment']=true;
    24.     $msg['content_type']=$content_type;
    25.     $msg['content_id']=$content_id; //Для вставки в тело письма
    26.     $msg['data']=$str;
    27.     $msg['name']=$name;
    28.     $msg['send_charset']='';
    29.     $msg['transfer_encoding']='base64';
    30.     array_push($this->parts,$msg);
    31.     }
    32.   //Функция, добавляющая тело сообщения
    33.   function body($content_type,$str){
    34.     $msg['attachment']=false;
    35.     $msg['content_type']=$content_type;
    36.     $msg['content_id']='';
    37.     $msg['data']=$str;
    38.     $msg['name']='';
    39.     $msg['send_charset']=$this->send_charset;
    40.     $msg['transfer_encoding']='8bit';//'quoted-printable';
    41.     array_push($this->parts,$msg);
    42.     }
    43.   //Функция для отправки multipart сообщения (с вложениями)
    44.   function send_multipart(){
    45.     $dc=$this->data_charset;
    46.     $sc=$this->send_charset;
    47.     $EOL=$this->EOL;
    48.     $boundary='a'.sha1(uniqid(time()));//любая строка, которой не будет в потоке данных.
    49.     //Encode some fields
    50.     $enc_to=mime_header_encode($this->to_name,$dc,$sc).' <'.$this->to_email.'>';
    51.     $enc_subject=mime_header_encode($this->subject,$dc,$sc);
    52.     if(!empty($this->from_email))
    53.        $enc_from=mime_header_encode($this->from_name, $dc, $sc).' <'.$this->from_email.'>';else
    54.        $enc_from='';
    55.     //Process data...
    56.     $multipart='';
    57.     for($i=0;$i<count($this->parts);$i++){
    58.       $ctype=$this->parts[$i]['content_type'];
    59.       $cname=$this->parts[$i]['name'];
    60.       $ccharset=$this->parts[$i]['send_charset'];
    61.       $ctenc=$this->parts[$i]['transfer_encoding'];
    62.       $cid=$this->parts[$i]['content_id'];
    63.       //Put file into multipart
    64.       $multipart.='--'.$boundary.$EOL;
    65.       $multipart.='Content-Type: '.$ctype.
    66.         (empty($ccharset)?'':'; charset='.$ccharset).
    67.         (empty($cname)?'':'; name='.$cname).$EOL;
    68.       if(!empty($cid))
    69.         $multipart.='Content-ID: <'.$cid.'>'.$EOL;
    70.       $multipart.='Content-Transfer-Encoding: '.$ctenc.$EOL;
    71.       //Different encodings
    72.       if($ctenc=='8bit'){//quoted-printable
    73.         $enc_body=$dc==$ccharset?
    74.           $this->parts[$i]['data']:
    75.           iconv($dc,$ccharset.'//IGNORE',$this->parts[$i]['data']);
    76.         $multipart.=$EOL.$enc_body.$EOL;
    77.         }else
    78.       if($ctenc=='base64'){
    79.         $multipart.=$EOL.chunk_split(base64_encode($this->parts[$i]['data']),76,$EOL).$EOL;
    80.         };
    81.       }
    82.     $multipart.='--'.$boundary.'--'.$EOL;
    83.     //
    84.     $headers='';
    85.     $headers.='Mime-Version: 1.0'.$EOL;
    86.     $headers.='Content-type: multipart/mixed; boundary='.$boundary.$EOL;
    87.     if(!empty($enc_from))
    88.        $headers.='From: '.$enc_from.$EOL;
    89.     //Send email
    90.     return mail($enc_to,$enc_subject,$multipart,$headers);
    91.     }
    92.   //Функция для отправки обычного сообщения
    93.   function send_single(){
    94.     //Get some global variables...
    95.     $dc=$this->data_charset;
    96.     $sc=$this->send_charset;
    97.     $EOL=$this->EOL;
    98.     $body=$this->parts[0]['data'];
    99.     $ctype=$this->parts[0]['content_type'];
    100.     $ccharset=$this->parts[0]['send_charset'];
    101.     //Encode some fields
    102.     $enc_to=mime_header_encode($this->to_name,$dc,$sc).' <'.$this->to_email.'>';
    103.     $enc_subject=mime_header_encode($this->subject,$dc,$sc);
    104.     if(!empty($this->from_email))
    105.        $enc_from=mime_header_encode($this->from_name, $dc, $sc).' <'.$this->from_email.'>';else
    106.        $enc_from='';
    107.     //Encode Body
    108.     $enc_body=$dc==$ccharset?$body:iconv($dc,$ccharset.'//IGNORE',$body);
    109.     //Form headers
    110.     $headers='';
    111.     $headers.='Mime-Version: 1.0'.$EOL;
    112.     $headers.='Content-type: '.$ctype.'; charset='.$ccharset.$EOL;
    113.     if(!empty($enc_from))
    114.        $headers.='From: '.$enc_from.$EOL;
    115.     //Send email
    116.     return mail($enc_to,$enc_subject,$enc_body,$headers);
    117.     }
    118.   function send(){
    119.     if(count($this->parts)==1) return $this->send_single(); else
    120.     if(count($this->parts)>1) return $this->send_multipart(); else
    121.       return false;
    122.     }
    123.   }

    Тут функция send() проверяет количество «кусочков». Если «кусочек» один, то отправляет его как текст. Ведь multipart нам не нужен, если мы отправляем только текст.

    Функции attachment() и body() прикрепляют текст или вложение. Принцип их работы, я думаю, понятен.

    Отправка писем с вложениями не представляет сложности. Тут я прикрепляю картинку и zip-архив:

    1.   require_once(dirname(__FILE__).'/email_api.php');
    2.   echo('Trying to send emails...<br>');
    3.   //HTML email
    4.   echo('Email with attachment - sending...<br>');
    5.   $email=new TEmail;
    6.   $email->from_email='noreply@konservs.com';
    7.   $email->from_name='От "Записок Консерваторов"';
    8.   $email->to_email='*********';
    9.   $email->subject='Тема (ІЇҐЭЄ іїґэє)';
    10.   $email->body('text/html','Письмо в HTML с вложениями.<br>'.
    11.     'Картинка:'.
    12.     '<img src="cid:cid1">'.
    13.     '<h1>Header 1 (Заголовок 1)</h1>'.
    14.     '<h2>Header 2 (Заголовок 2)</h2>'.
    15.     '<h3>Header 3 (Заголовок 3)</h3>'.
    16.     '<h4>Header 4 (Заголовок 4)</h4>'.
    17.     '<h5>Header 5 (Заголовок 5)</h5>'.
    18.     'Тест: ІЇҐЭЄ іїґэє');
    19.   $DS=DIRECTORY_SEPARATOR;
    20.   $email->attachment('image/jpeg','logo.jpg',dirname(__FILE__).$DS.'files'.$DS.'test.jpg','cid1');
    21.   $email->attachment('application/octet-stream','test.zip',dirname(__FILE__).$DS.'files'.$DS.'test.zip');
    22.   if($email->send())
    23.     echo('Email with attachment - OK.<br>'); else
    24.     echo('Email with attachment - Error!<br>');

    Пример письма, которое пришло мне.

    Письмо с вложением и картинкой

    Поздравляем! Вы научились отправлять письма с вложениями.

    Комментарии

    09.12.2014 05:37:54
    Avatar of МиколаМикола
    Постійно користуюся цим класом!
    Спасибі!
    26.12.2016 06:52:44
    Avatar of МиколаМикола
    ти не повіриш, але все ще користуюся)
    27.08.2019 03:50:19
    Avatar of ВадимВадим
    Как с вами связаться?

    Adding comments is temporarily disabled for unregistered users.

    Go Top