Содержание

Web-разработка • Yii2 и Laravel

Отправку почты рассмотрим на примере формы обратной связи с полями «Имя», «Почта» и «Сообщение». Нам потребуется создать контроллер, который будет показывать фому и обрабатывать POST-запрос от клиента. Потом добавим два роута и создам шаблон с формой. После этого нам потребуется создать класс FeedbackMailer, расширяющий Illuminate\Mail\Mailable и покопаться в настройках Laravel.

Форма обратной связи

Создаем контроллер FeedbackController:

> php artisan make:controller FeedbackController
namespace App\Http\Controllers;

use stdClass;
use App\Mail\FeedbackMailer;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;

class FeedbackController extends Controller {
    public function index() {
        return view('feedback.index');
    }

    public function send(Request $request) {
        $request->validate([
            'name' => 'required|max:100',
            'email' => 'required|email|max:100',
            'message' => 'required|max:500',
        ]);

        $data = new stdClass();
        $data->name = $request->name;
        $data->email = $request->email;
        $data->message = $request->message;
        Mail::to($data->email)->send(new FeedbackMailer($data));
        return redirect()->route('feedback.
index') ->with('success', 'Ваше сообщение успешно отправлено'); } }

Добавляем два маршрута в файл routes/web.php:

Route::get('/feedback', 'FeedbackController@index')->name('feedback.index');
Route::post('/feedback', 'FeedbackController@send')->name('feedback.send');

Создаем шаблон resources/views/feedback/index.blade.php:

@extends('layouts.app')

@section('content')
    <h2>Обратная связь</h2>
    @if (session('success'))
        <div role="alert">
            {{ session('success') }}
        </div>
    @endif
    @if ($errors->any())
        <div role="alert">
            <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
            </ul>
        </div>
    @endif
    <form method="post" action="{{ route('feedback.send') }}">
        @csrf
        <div>
            <input type="text" name="name" placeholder="Имя, фамилия"
                   required maxlength="100" value="{{ old('name') ?? '' }}">
        </div>
        <div>
            <input type="email" name="email" placeholder="Адрес почты"
                   required maxlength="100" value="{{ old('email') ?? '' }}">
        </div>
        <div>
        <textarea name="message" placeholder="Ваше сообщение"
                  required maxlength="500" rows="3">{{ old('message') ?? '' }}</textarea>
        </div>
        <div>
            <button type="submit">Отправить</button>
        </div>
    </form>
@endsection

Класс отправки почты

В Laravel каждый тип почтового сообщения (обратная связь, заказ в магазине), отправляемых приложением, представлен классом Mailable. Эти классы хранятся в директории app/Mail, которая будет создана при создании первого такого класса.

> php artisan make:mail FeedbackMailer
namespace App\Mail;

use stdClass;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class FeedbackMailer extends Mailable {

    use Queueable, SerializesModels;

    private $data;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct(stdClass $data) {
        $this->data = $data;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build() {
        return $this->from('[email protected]', 'ООО ТД АВРОРА')
            ->subject('Форма обратной связи')
            ->view('email.feedback', ['data' => $this->data]);
    }
}

Чтобы не указывать заголовок письма From (от кого), можно задать это в файле .

env:

APP_NAME="ООО ТД АВРОРА"
[email protected]
MAIL_FROM_NAME="${APP_NAME}"

Эти три значения используются далее в файле конфигурации отправки почты config/mail.php:

return [
    /* ... */
    'from' => [
        'address' => env('MAIL_FROM_ADDRESS', '[email protected]'),
        'name' => env('MAIL_FROM_NAME', 'Example'),
    ],
    /* ... */
];
class FeedbackMailer extends Mailable {
    /* ... */
    public function build() {
        return $this->subject('Форма обратной связи')->view('email.feedback', ['data' => $this->data]);
    }
}

Шаблон почтового сообщения

Еще нам потребуется шаблон для письма

resources/views/email/feedback.blade.php:

<h2>Форма обратной связи</h2>

<p><strong>Имя:</strong> {{ $data->name }}</p>
<p><strong>Почта:</strong> {{ $data->email }}</p>
<p><strong>Сообщение:</strong> {{ $data->message }}</p>

Отправка почты в log-файл

Теперь настройки Laravel для отправки писем. Для начала будем записывать письма просто в log-файл, для этого редактируем файл .env:

MAIL_MAILER=log

Эта настройка используется в файле конфигурации

config/mail.php, где можно задать, с помощью какого mailer-а будут отправляться письма:

return [

    /*
     * Default Mailer
     */
    'default' => env('MAIL_MAILER', 'smtp'),

    /*
     * Mailer Configurations
     */
    'mailers' => [
        'smtp' => [
            'transport' => 'smtp',
            'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
            'port' => env('MAIL_PORT', 587),
            'encryption' => env('MAIL_ENCRYPTION', 'tls'),
            'username' => env('MAIL_USERNAME'),
            'password' => env('MAIL_PASSWORD'),
            'timeout' => null,
            'auth_mode' => null,
        ],

        'ses' => [
            'transport' => 'ses',
        ],

        'mailgun' => [
            'transport' => 'mailgun',
        ],

        'postmark' => [
            'transport' => 'postmark',
        ],

        'sendmail' => [
            'transport' => 'sendmail',
            'path' => '/usr/sbin/sendmail -bs',
        ],

        'log' => [
            'transport' => 'log',
            'channel' => env('MAIL_LOG_CHANNEL'),
        ],

        'array' => [
            'transport' => 'array',
        ],
    ],

    /*
     * Global From: Address
     */
    'from' => [
        'address' => env('MAIL_FROM_ADDRESS', 'hello@example.
com'), 'name' => env('MAIL_FROM_NAME', 'Example'), ], /* * Markdown Mail Settings */ 'markdown' => [ 'theme' => 'default', 'paths' => [ resource_path('views/vendor/mail'), ], ], ];

Теперь отправленные письма будут записываться в log-файл, где их можно посмотреть:

Но не очень удобно, что письма записываются в один файл с сообщениями об ошибках. Так что создадим еще одну настройку в файле .env:

MAIL_LOG_CHANNEL=maillog

И добавим еще один канал (channel) в файле конфигурации логов приложения

config/logging.php:

return [
    'channels' => [
        /* ... */
        'maillog' => [
            'driver' => 'single',
            'path' => storage_path('mails/laravel.log'),
        ],
    ],
];

Теперь письма будут все так же записываться в лог-файл, но в директорию storage/mails.

Отправка через smtp-сервер

Отправлять будем через smtp-сервер Яндекса, для этого нужно получить пароль приложения здесь:

После этого редактируем файл конфигурации приложения .env:

APP_NAME="ООО ТД АВРОРА"
MAIL_MAILER=smtp
MAIL_HOST=smtp.yandex.ru
MAIL_PORT=465
[email protected]
MAIL_PASSWORD=zsfmsbxwdnbuanjk
MAIL_ENCRYPTION=ssl
[email protected]
MAIL_FROM_NAME="${APP_NAME}"

Файл вложения

Давайте добавим на форму еще одно поле для загрузки изображения и будем это изображение прикреплять к письму:

@extends('layouts.app')

@section('content')
    <h2>Обратная связь</h2>
    @if (session('success'))
        <div role="alert">
            {{ session('success') }}
        </div>
    @endif
    @if ($errors->any())
        <div role="alert">
            <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
            </ul>
        </div>
    @endif
    <form method="post" action="{{ route('feedback.
send') }}" enctype="multipart/form-data"> @csrf <div> <input type="text" name="name" placeholder="Имя, фамилия" required maxlength="100" value="{{ old('name') ?? '' }}"> </div> <div> <input type="email" name="email" placeholder="Адрес почты" required maxlength="100" value="{{ old('email') ?? '' }}"> </div> <div> <textarea name="message" placeholder="Ваше сообщение" required maxlength="500" rows="3">{{ old('message') ?? '' }}</textarea> </div> <div> <input type="file" name="image" accept="image/png, image/jpeg"> </div> <div> <button type="submit">Отправить</button> </div> </form> @endsection
namespace App\Http\Controllers;

use stdClass;
use App\Mail\FeedbackMailer;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;

class FeedbackController extends Controller {
    public function index() {
        return view('feedback. index');
    }

    public function send(Request $request) {
        $request->validate([
            'name' => 'required|max:100',
            'email' => 'required|email|max:100',
            'message' => 'required|max:500',
            'image' => 'mimes:jpeg,jpg,png|max:5000',
        ]);
        $image = $request->file('image');
        if ($image) { // был загружен файл изображения
            $raw = $image->get();
            $ext = $image->extension();
        }
        $data = new stdClass();
        $data->name = $request->name;
        $data->email = $request->email;
        $data->message = $request->message;
        $data->image = $raw ?? null;
        $data->ext = $ext ?? null;
        Mail::to($data->email)->send(new FeedbackMailer($data));
        return redirect()->route('feedback.index')
            ->with('success', 'Ваше сообщение успешно отправлено');
    }
}
namespace App\Mail;

use Illuminate\Support\Facades\Storage;
use stdClass;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class FeedbackMailer extends Mailable {

    use Queueable, SerializesModels;

    public $data;

    public function __construct(stdClass $feedback) {
        $this->data = $feedback;
    }

    public function build() {
        if ($this->data->image) {
            $this->attachData($this->data->image, 'image. '.$this->data->ext);
        }
        $this->subject('Форма обратной связи')
            ->view('email.feedback');
    }
}

Мы получаем из объекта http-запроса сырую строку файла и передаем классу FeedbackMailer. Но можно еще прикрепить файл из хранилища с помощью методов attachFromStorage() (используется диск по умолчанию) или attachFromStorageDisk() (диск надо указать самостоятельно).

class FeedbackController extends Controller {
    /* ... */
    public function send(Request $request) {
        /* ... */
        $image = $request->file('image');
        if ($image) { // был загружен файл изображения
            $path = $image->store('feedback', 'local');
        }
        $data = new stdClass();
        /* ... */
        $data->image = $path ?? null;
        Mail::to($data->email)->send(new FeedbackMailer($data));
        return redirect()->route('feedback.index')
            ->with('success', 'Ваше сообщение успешно отправлено');
    }
}
class FeedbackMailer extends Mailable {
    /* . .. */
    public function build() {
        if ($this->data->image) {
            $this->attachFromStorageDisk('local', $this->data->image);
        }
        $this->subject('Форма обратной связи')
            ->view('email.feedback');
    }
}

Мы сохраняем загруженное изображение в директорию storage/app/feedback и потом оттуда прикрепляем к письму. Смысла хранить изображение дальше нет, так что его можно удалить. Но сразу удалять нельзя — возникает ошибка, потому что файл удаляется до того, как будет прикреплен к письму. Видимо, нужно добавить обработчик события MessageSent (возникает после отправки) — и уже там удалить файл с диска.

Вместо заключения

Передать данные в шаблон можно через публичное свойство класса FeedbackMailer:

class FeedbackMailer extends Mailable {

    use Queueable, SerializesModels;

    public $data;

    public function __construct(stdClass $data) {
        $this->data = $data;
    }

    public function build() {
        return $this->subject('Форма обратной связи')->view('email. feedback');
    }
}

Чтобы изменить данные, прежде чем передать их шаблону, свойство должно быть объявлено как protected или private:

class FeedbackMailer extends Mailable {

    use Queueable, SerializesModels;

    private $data;

    public function __construct(stdClass $data) {
        $this->data = $data;
    }

    public function build() {
        return $this->subject('Форма обратной связи')
            ->view('email.feedback')
            ->with([
                'name' => $this->data->name,
                'email' => $this->data->email,
                'message' => $this->data->message,
            ]);;
    }
}

Метод withSwiftMessage() класса Mailable позволяет зарегистрировать анонимную функцию, которая будет вызываться экземпляром сообщения SwiftMailer перед отправкой сообщения. Это дает возможность кастомизировать сообщение перед тем как оно будет доставлено.

class FeedbackMailer extends Mailable {
    /* ... */
    public function build() {
        $this->subject('Форма обратной связи')
            ->view('email.feedback');
        $this->withSwiftMessage(function ($message) {
            $message->getHeaders()->addTextHeader('Custom-Header', 'HeaderValue');
        });
    }
}

Поиск: Laravel • PHP • POST • Web-разработка • Класс • Форма • Фреймворк • Письмо • Mailable • Теория

PHP на IIS отправка электронной почты msmtp

Столкнулся с необходимостью отправки электронной почты из PHP скриптов исполняющихся под Windows IIS. В принципе не такая сложная задача, но она омрачалась тем, что отправка должна осуществляться от имени почтового ящика расположенного на сервере Yandex. Но тут начинаются основные грабли. Не буду описывать, то почему так сложилось, но задача стояла именно так. Следовало отправлять почту используя SMTP сервер Яндекса.

Поискав по сети нашел массу интересной инфы, но применяя на практике программы почему-то не хотели корректно отправлять почту. Их постоянно отшивал сервер Яндекса со следующей мотивировкой:

15.03.02 12:32:07 : Working without SSL/TLS encryption is not allowed. Please visit http://help.yandex.ru/mail/mail-clients/ssl.xml sc=BWCTvUcYASw9

Конечно, по ссылке всё было именно так как я настраивал в программе sendmail.exe. Постепенно обыскивая интернет, я нашел, что для отправки почты Битрикс использует консольный клиент под названием MSMTP. Скачал, попробовал его в работе с почтой Яндекса и пришел к выводу, что это именно то, что мне необходимо.

И так, пара тонкостей которые необходимо учесть. Они были обнаружены не сразу, но это съэкономит вам время на поиски проблемы.

Во-первых, конфигурационный файл для этой программы должен называться msmtprc.txt. Во-вторых, он должен располагаться не рядом с программой, а в каталоге C:ProgramData.

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

account default
logfile C:sendmailmsmtp.log
host smtp.yandex.ru
port 587
from [email protected]
keepbcc on
auth on
user [email protected]
password PassWordDlaPochty123
tls on
tls_starttls on
tls_certcheck off

Естественно, что имя учётной записи и пароль от учётки необходимо вписать свои. Порт изменять не стоит, там действительно указывается 587.

И так, распаковываем программу на диск, в каталог c:sendmail Создаём конфигурационный файл для программы. За тем нужно отредактировать конфигурационный файл интерпретатора PHP. Он расположен в каталоге в который вы установили PHP.

Отредактируйте секцию mail function следующим образом:

[mail function]
; For Win32 only.
; http://php.net/smtp
;SMTP = localhost
; http://php.net/smtp-port
;smtp_port = 25

; For Win32 only.
; http://php.net/sendmail-from
sendmail_from = [email protected]

; For Unix only.  You may supply arguments as well (default: "sendmail -t -i").
; http://php.net/sendmail-path
sendmail_path = "c:sendmailmsmtp.exe -t"

Теоретически, после перезапуска интерпретатора, ваша функция отправки почты станет работать. Кстати, н езабывайте о том, что адрес отправителя необходимо указывать свой, соответствующий учетной записи на сервере Яндекс. Если указать другой адрес, то почтовый сервер заблокирует письмо и не отправит его.

Программу можно скачать с сайта MSMTP.

Тэги: ИТ, программирование

Отредактировано:2020-09-10 19:56:20

Как настроить XAMPP для отправки почты с локального хоста с помощью PHP?

PHP, PHP программы, Веб-технологии, Веб-технологии Вопросы

Чтобы настроить сервер XAMPP для отправки почты с локального хоста, мы должны внести изменения в два файла sendmail.ini и php.ini. Откройте папку xampp. По имени «sendmail.ini» присутствует в файле sendmail, а «php.ini» присутствует в файле php в папке xampp .

Шаг 1:

  • Перейдите в C: / xampp / sendmail: откройте файл sendmail.ini в блокноте или любом текстовом редакторе и внесите следующие изменения.
    change smtp_server=mail.yourdomain.com to smtp_server=smtp.gmail.com
    change smtp_port to smtp_port=587
    change smtp_ssl=auto to smtp_ssl=tls

    uncomment ;error_logfile=error. log to error_logfile=error.log
    uncomment ;debug_logfile=debug.log to debug_logfile=debug.log
    write your gmail id in auth_username: auth_username=*****@gmail.com
    write your gmail assword in auth_password: auth_password=*****

    write your gmail id in force_sender: *****@gmail.com
    change hostname to hostname=localhost

Шаг 2

  • Перейдите в C: / xampp / php: откройте файл php.ini в блокноте или в любом текстовом редакторе, перейдите в [mail function] и внесите следующие изменения.
    comment SMTP=localhost by putting semicolon infront=>;SMTP=localhost
    comment smtp_port=25 by putting semicolon infront=>;smtp_port=25
    comment sendmail_from= by putting semicolon infront=>;sendmail_from=specify path of
     file in sendmail_path to sendmail_path=C:\xampp\sendmail\sendmail.exe
    
    check if extension=php_openssl.dll is enabled=>If there is semicolon in front then
     un-comment it by removing that semicolon
    


    После выполнения указанных шагов, если письмо не было отправлено с помощью функции mail, перейдите в C: / xampp / sendmail и откройте error. log, чтобы увидеть, что произошла ошибка.

Примечание. Здесь показана процедура для gmail, но ее можно распространить на другие письма, изменив сервер smtp и номер порта. При использовании gmail позаботьтесь о том, чтобы включить параметр, позволяющий получить доступ к менее защищенному веб-приложению.

Рекомендуемые посты:

Как настроить XAMPP для отправки почты с локального хоста с помощью PHP?

0.00 (0%) 0 votes

Отправить почту PHP HTML с вложениями

Если вы действительно хотите узнать, как отформатировать Интернет-сообщение, вам следует обратиться к его запросу комментариев (он же RFC). Документ RFC2045, выпущенный в ноябре 1996 г., определяет «Многоцелевые расширения почты Интернета — формат тел сообщений Интернета».

Формат как-то очень строгий, и его нужно соблюдать как есть.

Обычно сообщение содержит заголовок и тело. Заголовок определяет тип сообщения, способ его форматирования и некоторые другие поля, которые отличаются от одного типа к другому.

Тело состоит из разных сущностей. Сущность может быть, например, просто обычным текстом вроде «Привет!» но также может быть изображением, вложением, чем угодно.

ПРИМЕЧАНИЕ В следующих примерах все, что заключено в квадратные скобки (например, {hello}), следует заменить на ваше реальное значение. Любая новая строка на самом деле является CRLF (например, ASCII 13 + ASCII 10). Где вы видите, что к нему прилипают два CRLF. Это был бы худший момент, чтобы показать, насколько вы креативны.

В основном для сообщения электронной почты с вложениями заголовок должен выглядеть так:

  MIME-версия: 1.0
Кому: {email @ domain}
Тема: {email-subject}
X-Priority: {2 (высокий)}
Content-Type: составной / смешанный; border = "{смешанный-boudary}"
  

В приведенном выше примере {mixed-boudary} может быть любым уникальным значением хеш-функции, например 000008050800060107020705. Остальные не требуют пояснений.

Теперь, когда мы хотим добавить новый объект к сообщению (например, тело сообщения, изображение, вложение), мы должны сообщить почтовому агенту, что прибывает новый раздел , т.е. для добавления к этому объекту префикса значения {смешанная граница}.Мы называем это «открытой границей». Обратите внимание, что, открывая границу, мы не вставляем эту границу, как было определено изначально, мы используем еще два знака минус впереди, например — {mixed-boudary}. Когда мы закрываем границу, мы действуем аналогичным образом, за исключением того, что мы должны использовать еще 2 знака минус в конце, например — {mixed-boudary} —

  - {смешанный-баударный}
содержание сущности
- {смешанный-boudary} -
  

Поскольку почтовый агент должен понимать, какой тип имеет содержимое нашей новой вставленной сущности, мы должны объявить это сразу после открытия границы.Объявление — это просто заголовок, который содержит только те параметры / значения, которые совместимы с сущностью.

Для содержимого тела HTML мой заголовок объекта будет выглядеть так:

  Content-Type: текст / html; charset = utf-8
Кодирование передачи содержимого: 7 бит
  

, так что все тело (заключенное в границы), наконец, будет выглядеть так:

  - {смешанный-баударный}
Тип содержимого: текст / html; charset = utf-8
Кодирование передачи содержимого: 7 бит


  

Lorem ipsum dolor sit amet, conctetur adipiscing elit.Пеллентеский бархат
dapibus arcu. Duis quam dui, ornare non mi nec, luctus faucibus massa. Вивамус
Quis Purus в erat euismod ullamcorper vitae eget dolor. Aliquam tempor erat
accumsan, conctetur ex et, rhoncus risus. 

  

Если необходимо вставить еще один объект, мы действуем точно так же, как указано выше. Когда больше нет данных для добавления к сообщению, мы закрываем смешанную границу, т. е. CRLF + — {смешанный язык} -.

Если по какой-либо причине объект должен быть вставлен с альтернативным представлением (например,тело сообщения вставляется как в формате обычного текста, так и в формате HTML), тогда содержимое сущности должно быть объявлено с помощью multipart / alternate типа содержимого (хотя глобальный заголовок multipart / mixed все еще остается!) Каждое альтернативное представление будет заключено в эту новую границу.

Полный пример ниже:

  MIME-версия: 1.0
Кому: {email @ domain}
Тема: {email-subject}
X-Priority: {2 (высокий)}
Content-Type: составной / смешанный; border = "{смешанный-boudary}"

- {смешанный-boudary}
Content-Type: составной / альтернативный; border = "{альтернативный-boudary}"

- {альтернатива-boudary}
Content-Type: текст / простой; charset = utf-8;
Кодирование передачи содержимого: 7 бит

Lorem ipsum dolor sit amet, conctetur adipiscing elit.Пеллентеский бархат
dapibus arcu. Duis quam dui, ornare non mi nec, luctus faucibus massa.  Вивамус
Quis Purus в erat euismod ullamcorper vitae eget dolor. Aliquam tempor erat
accumsan, conctetur ex et, rhoncus risus.

- {альтернатива-boudary}
Тип содержимого: текст / html; charset = utf-8;
Кодирование передачи содержимого: 7 бит


  

Lorem ipsum dolor sit amet, conctetur adipiscing elit.Пеллентеский бархат
dapibus arcu. Duis quam dui, ornare non mi nec, luctus faucibus massa. Вивамус
Quis Purus в erat euismod ullamcorper vitae eget dolor. Aliquam tempor erat
accumsan, conctetur ex et, rhoncus risus.



- {альтернатива-boudary} -

- {смешанный-boudary}
Content-Type: application / pdf; name = "myfile.pdf"
Кодирование передачи содержимого: base64
Content-Disposition: вложение; filename = "myfile.pdf"

JVBERi0xLjINOCAwIG9iag08PCAvTGVuZ3RoIDkgMCBSIC9GaWx0ZXIgL0ZsYXRlRGVjb2Rl
ID4 + DXN0cmVhbQ1oQ51bbY / cNg7 + BfsfhAUO11w3riW / B7gPaZEAAdpcm06RL8EBzoyn68uM
vZ3xZLv // khKsuUxNaMNiiabpUg + pKiHsmxJEcN / UsgiilP4ab2 / + XF1I81vszSqclHIOEpj
sdrf / PC2EFVUpmK1vXkZxVKs1uJlJJVYPYrvPra7XVvvxYdIrE7rL83hhVj97 + bNyjUoFam7
FnOB + tubGI3FZEkwmhpKXpVRnqJi0PCyjBJ1DjyOYqWBxxXp / 1h4X + ov9abZt434pV0feoG /
ars / xU / 9 / qEZmm7diJ + abmgOr0TGeFNFEuXx5M4B95Idns / QAaJMI1IpKeXi9 + ZhaPafm4NQ
cRwzNpK0iirlRvisRBZpVJa + PP51091kkjBWBXrJxUuZRjIXh0Z8FN3MnB5X5st5Kay9355n

- {смешанный-boudary} -
  

СОВЕТЫ

Используйте предпочтительный почтовый клиент (у меня Thunderbird) и отправьте на только одно сообщение в виде обычного текста, только один HTML, одно смешанное и затем каждое из предыдущих, но с одним вложенным файлом. Когда вы получаете сообщение, просто изучите его источник (Просмотр -> Сообщение источник).

@Edit: очень хорошо документированный пример использования + пример PHP можно найти здесь

Отправка вложений с помощью PHP Mail ()

if (isset ($ _ POST) &&! Empty ($ _ POST)) {

if (! Empty ($ _ FILES [‘attachment’] [‘ имя ‘])) {

$ file_name = $ _FILES [‘ вложение ‘] [‘ имя ‘];

$ temp_name = $ _FILES [‘вложение’] [‘tmp_name’];

$ file_type = $ _FILES [‘вложение’] [‘тип’];

$ base = базовое имя ($ имя_файла);

$ extension = substr ($ base, strlen ($ base) -4, strlen ($ base));

// разрешены только эти типы файлов

$ allowed_extensions = array («.doc «,» docx «,» .pdf «,» .zip «,» .png «);

// проверяем, разрешен ли этот тип файла

if (in_array ($ extension, $ allowed_extensions)) {

// основные сведения о почте

$ from = $ _POST [‘user_mail’];

$ to = «phpcodertech@gmail. com»;

$ subject = $ _POST [‘user_name’];

$ message = $ _POST [‘user_message’];

// вещи, которые вам нужны

$ file = $ temp_name;

$ content = chunk_split (base64_encode (file_get_contents ($ file)));

$ uid = md5 (uniqid5 (uniqid5) (time ())); // уникальный идентификатор

// стандартные почтовые заголовки

$ header = «From:».$ от. «\ r \ n»;

$ header. = «Reply-To:». $ Replyto. «\ г \ п»;

$ header. = «Версия MIME: 1.0 \ r \ n»;

// объявляем несколько типов электронной почты (простой текст + attch)

$ header. = «Content-Type: multipart / mixed; Border = \» «. $ Uid.» \ «\ R \ n «;

$ header. = «Это сообщение, состоящее из нескольких частей, в формате MIME. \ R \ n»;

// часть обычного текста

$ header.= «-«. $ uid. «\ r \ n»;

$ header. = «Content-type: text / plain; charset = iso-8859-1 \ r \ n»;

$ header. = «Content-Transfer-Encoding: 7bit \ r \ n»;

$ header. = $ Message. «\ г \ п»;

// часть атрибута

$ header. = «-«. $ Uid. «\ R \ n»;

$ header. = «Content-Type:». $ File_type. «; Name = \» «. $ File_name.» \ «\ R \ n»;

$ header. = «Content-Transfer-Encoding: base64 \ r \ n»;

$ заголовок.= «Content-Disposition: attachment; filename = \» «. $ File_name.» \ «\ R \ n»;

$ header. = $ Content. «\ R \ n»; // забросил 64 закодированных attch

// отправка почты — сообщение находится не здесь, а в заголовке, состоящем из нескольких частей

if (mail ($ to, $ subject, $ message, $ заголовок)) {

эхо «успех»;

} else {

эхо «сбой»;

echo error_get_last () [‘сообщение’];

}

} else {

echo «тип файла не разрешен»; } // выводить html-файл

} else {

echo «файл не отправлен»; }

}

?>

name = «user_mail»>