Php imap приклади. Поштові функції imap у РНР. Папки електронної пошти

Головна / Корисна інформація

Одним із можливих застосувань imap функцій є створення поштового демона, який керуватиме підпискою та відпискою користувачів від вашої поштової розсилки. Для реалізації цього завдання зазвичай у розсилках використовуються два методи. Перший припускає, що користувач повинен зайти на якусь сторінку та підтвердити свої дії, другий вимагає надсилання листа. Другий також вимагає, щоб скрипт-обробник регулярно запускався cron daemon-om. Через це він не такий популярний як перший спосіб.

Але, як можна помітити, найсерйозніші розсилки використовують другий спосіб. Тому, якщо у вас є можливість використання cron, скористайтеся ним.

Власне, розібратися у функціях не складно. Деякі труднощі можуть виникнути з розбором заголовків листів, які оброблятимуть скрипт.

Алгоритм роботи самого скрипта вигадати нескладно. Демон встановлює з'єднання з поштовим сервером, і перевіряє наявність листів. Якщо листів немає, робота скрипта припиняється. Якщо листи є, відбувається розбір заголовків першого листа. Проглядається поля from та subject. Якщо поле subject містить один із двох допустимих варіантів заголовка (підписка або відписка), то запис, якому відповідає значення поля from або стає активним (підтвердженим), або видаляється з таблиці. В обох випадках на адресу, вказану в полі від посилається відповідне повідомлення про дії скрипта. Після цього лист позначається видалення. Якщо subject не містить допустимих тем, надсилається повідомлення про помилку, і лист також позначається для видалення. Потім скрипт переходить до наступного листа. Закінчивши розбір усіх листів, він очищає ящик.

Для відкриття скриньки використовується функція imap_open. Оскільки PHP підтримує роботу з кількома протоколами, необхідно явно вказати, який протокол використовується для роботи зі скринькою. У нашому випадку це pop3 на 110 портах (стандарт). Привласнюємо результат виконання скрипта змінної $my_box.

$my_box = imap_open("(you.pop.host/pop3:110)", "login", "password");

Надалі ви побачите, що ця змінна буде використовуватися практично у всіх imap функціях. Далі перевіряємо ящик на наявність листів. Перевірку виконує функція imap_num_msg.

$n = imap_num_msg($my_box);

В результаті змінна $n міститиме кількість листів у ящику. Число це може бути або більше за нуль, або дорівнює йому (якщо ящик порожній). Якщо листи є, то циклі while виконуємо розбір листів, послідовно збільшуючи номер листи на одиницю. Зверніть увагу, що перший лист в ящику буде мати номер 0, як і перший елемент масиву. Для збільшення номера листа, привласнюємо змінною $m значення 0, а потім за умов виконання циклу збільшуємо її на одиницю $m++.

Для аналізу цікавих нас заголовків достатньо двох функцій: imap_header і imap_fetch_overview . Для виконання кожної з них, крім скриньки, необхідно вказувати номер листа. У нашому випадку, всередині циклу він дорівнюватиме змінній $m.

imap_header повертає в результаті виконання об'єкт, що містить вичерпну інформацію про заголовок листа. Серед іншого, цей об'єкт містить масив від якого містить чотири значення. Це personal, adl, mailbox та host. Нас із них цікавлять лише mailbox та host. Підставляючи їх, ми отримаємо адресу, з якої було надіслано листа.

$ h = imap_header ($ my_box, $ m); $ h = $ h -> from; foreach ($h as $k => $v) ( $mailbox = $v->mailbox; $host = $v->host; $personal = $v->personal; $email = $mailbox . "@" . $host;

imap_fetch_overview – дозволить нам дізнатися тему листа. Для цих же цілей можна було б використовувати і imap_header, але з ряду причин це іноді може не спрацювати. З масиву, який повертає ця функція, нам потрібне лише поле subject

$s = imap_fetch_overview($my_box, $m); foreach ($s як $k => $v) $subj = $v->subject;

Подальші наші дії зводяться до того, щоб витягнути email з бази, і в разі наявності його там, помітити весь рядок з цим записом як або видалити. Припустимо, що після заповнення форми розсилки на сайті передплатнику надається статус 0, а після підтвердження підписки він змінюється на 1.

If ($subj == "subscribe") ( mysql_query("update subscribe set stat=1 where email=$my_email"); $del = imap_delete($my_box, $m); mail($email, $add_sbj, $add_text , $headers); ) else if ($subj == "unsubscribe") ( mysql_query("delete from subscribe where email = $my_email"); $del = imap_delete($my_box, $m); mail($email, $ del_sbj, $del_text, $headers);) else ( $del = imap_delete($my_box, $m); mail($email, $err_sbj, $err_text, $headers); ) після виконання всіх дій скрипт очищає скриньку. $clear = imap_expunge($my_box);

Дана найпростіша програма, лише демонстрація того, що на PHP можна писати не тільки сайти, що динамічно змінюються, а й сервіси, які користувачеві взагалі не видно.

Лістинг усієї програми за винятком параметрів з'єднання з базою:

Include "config.php"; // з'єднання з БД $my_box = imap_open("(you.pop.host/pop3:110)", "login", "password"); $n = imap_num_msg($my_box); $ m = 0; $add_text = "Дякую за підтвердження вашої підписки"; $add_sbj = "you added!"; $del_text = "Ви були видалені зі списку розсилки."; $del_sbj = "delete from list"; $err_text = "Вибачте, але ця поштова скринька використовується тільки для адміністрування розсилки"; $err_sbj = "error"; $headers = "from: subscribe robot x-mailer: php4 content-type: text/plain; charset=windows-1251"; if($n != 0) ( while($m++< $n) { $h = imap_header($my_box, $m); $s = imap_fetch_overview($my_box, $m); $h = $h->from; foreach ($h as $k =>$v) ( $mailbox = $v->mailbox; $host = $v->host; $personal = $v->personal; $email = $mailbox . "@" . $host, $my_email = mysql_escape_string($email); if ($subj == "subscribe") ( mysql_query("update table set stat=1 where email=$my_email"); //print mysql_error(); $del = imap_delete($my_box, $m); mail($ email, $add_sbj, $add_text, $headers); ) else if ($subj == "unsubscribe") ( mysql_query("delete from table where email = $my_email"); mail ($email, $del_sbj, $del_text, $headers); ) else ( $del = imap_delete($open_box, $m); mail($email, $err_sbj, $err_text, $headers); ) ) $clear = imap_expunge($my_box); )

У лістингу відсутні деякі деталі, наприклад можливе конвертування з win у koi поштової скринькивідправника і т.д. Це вже функціональні надмірності, які кожен може додати за необхідності.

Деякі веб-програми можуть вимагати особливої ​​електронної пошти для користувача. У такому разі ми можемо написати свій власний код електронної пошти SquirrelMail або Roundcube . Незалежно від того, що ви оберете, знання роботи з поштою IMAP буде корисним.

Як працювати з IMAP у PHP розповідається на двох сторінках. На першій сторінці необхідні функції для підключення до поштовим серверамта читання повідомлень. На другій сторінці поговоримо про роботу з електронною поштою, наприклад, видалення повідомлень, завантаження програм тощо.

Щоб продемонструвати функціональні можливості, використовуватимуться приклади коду, які можна використовувати для запуску сценаріїв власного поштового клієнта.

Параметри URL-адреси для виклику потрібних функцій:

  • func - тип функції, необхідні (наприклад: читати електронну пошту, переглядати поштову скриньку, видалити повідомлення)
  • folder - ім'я папки поштової скриньки для підключення (наприклад: Вхідні, Надіслані, спам)
  • uid – унікальний ідентифікатор електронної пошти

Параметри можна отримати за допомогою $_GET та switch можуть бути використані для виклику відповідних дій.

Підключення до сервера IMAP

Для встановлення з'єднання з сервером IMAP ми використовуємо функцію imap_connect() , як показано нижче:

Шлях повідомлення, ім'я користувача та пароль необхідні параметри для підключення до сервера. Ви можете дізнатися про додаткові параметри в посібнику.

Шлях до поштової скриньки є рядком, який ідентифікує сервер і порт у фігурних дужках визначає ім'я потрібної папки пошти.

Ось кілька рядків для папки Вхідніпоштових служб:

  • Gmail (imap.gmail.com: 993/imap/ssl) INBOX
  • Yahoo (imap.mail.yahoo.com: 993/imap/ssl) INBOX
  • AOL (imap.aol.com: 993/imap/ssl) INBOX

На деяких серверах не увімкнено SSL, у цьому випадку Вам потрібно буде опустити SSL з рядка. Інші сервери можуть використовувати власні сертифікати, у яких ви повинні увімкнути NOVALIDATE-CERT.

З відкритим підключенням до поштового сервера, ми можемо тепер поглянути на функції, які використовуються для таких видів діяльності:

  • Відображення списку папки поштової скриньки у вашому обліковому записі електронної пошти
  • Відображення списку електронних листів у папці
  • Перегляд вмісту електронної пошти автора

Папки електронної пошти

Вхідні , Надіслані , Сміттяі Спам— ці папки видно практично в кожному обліковому записі електронної пошти, і користувачі можуть часто створювати власні папки. Щоб переглянути повідомлення в цих папках, ми повинні змінити наш рядок підключення. Наприклад, застосувати «INBOX» (Вхідні) у рядку шляху раніше. Якщо потрібно, підключитися до папки для спаму, використовуйте щось на зразок Spam (Спам) замість цього. Але хоча це може бути перераховане як Спамв обліковий запис електронної пошти, якщо дивитися через поштового клієнта, справжня назва папок у фоні може бути різною. Ми можемо перерахувати всі наявні папки облікового запису за допомогою imap_list() .

"; foreach ($folders as $folder) ( $folder = str_replace("(imap.gmail..php?folder=" . $folder . "&func=view">" . $folder . "";) echo "";

Ми повинні передати дескриптор з'єднання, отримані з imap_open() як вихідний параметр imap_list() . Ми також повинні пройти шлях (без папки, наприклад, INBOX). Третім параметром є запит усіх доступних папок.

Повідомлення про повідомлення

Кожна папка містить список доступних повідомлень електронної пошти, тому давайте подивимося, як ми можемо створити список повідомлень у нашій поштовій скриньці.

Спочатку потрібно отримати кількість повідомлень, доступних за допомогою imap_num_msg(). Потім ми можемо використовувати функцію imap_header() для отримання інформації для заголовка кожного повідомлення.

Скажімо, якщо ми хочемо останніх 20 листів:

($numMessages - 20); $i--) ( $header = imap_header($imap, $i); $fromInfo = $header->from; $replyInfo = $header->reply_to; $details = array("fromAddr" => (isset($) fromInfo->mailbox) && isset($fromInfo->host)) ? $fromInfo->mailbox . "@" . $fromInfo->host: "", "fromName" => $fromInfo->personal: "", "replyAddr" => (isset($replyInfo->mailbox) && isset($replyInfo->host)) ? $replyInfo->mailbox . "@" . $replyInfo->host : "", "replyName" => (isset($replyTo->personal)) ? $replyto->personal: "", "subject" => (isset($header->subject)) ? $header->subject : "", "udate" => (isset($header->udate)) ? $header->udate: ""); $uid = imap_uid($imap, $i);

    "; echo"
  • Від:$details["fromName"]; echo " " . $details["fromAddr"] .
  • "; echo"
  • Subject:" . $details["subject"] ..php?folder=" . $folder . "&uid=" . $uid ..php?folder=" . $folder . "&uid=" . $uid . "&func=delete">Delete
  • "; echo"
"; }

З'єднання $Imap повинні бути відкриті у потрібній папці. Ми можемо пройти через останні 20 листів з використанням кількості повідомлень, отриманих imap_num_msg() . Зв'язок і номер електронної пошти даються imap_header() , щоб отримати інформацію про заголовок, який потім може бути перинять за цікаву інформацію від відправника, адресу електронної пошти, ім'я, тема і т.д

Зверніть увагу, що номер електронної пошти від загальної кількості повідомлень не є унікальним ідентифікатором для повідомлення. Якщо у вас є 100 листів у поштовій скриньці, то останнє число буде 100, попередня буде 99, і так далі. Якщо видалити повідомлення під номером 100, а потім отримуєте нове повідомлення, його номер буде 100.

Щоб розпочати наступні дії, потрібно отримати унікальний ідентифікатор для електронної пошти. Кожен лист має унікальний ідентифікатор, званий UID, який ми можемо отримати, надаючи електронну пошту, функція номера imap_uid() UID-унікальний і не змінюватиметься з часом.

Перегляд змісту повідомлення

Читання електронної пошти насправді не така проста справа, як попередні завдання, тому потрібно використовувати класи пошти розроблені Мітул Корадія. У класі адаптовані такі три функції для нашого прикладу:

encoding) ( case 3: return imap_base64($text); case 4: return imap_qprint($text); default: return $text; ) ) // multipart if ($structure->type == 1) ( foreach ($structure ->parts as $index => $subStruct) ( $prefix = ""; if ($partNumber) ( $prefix = $partNumber . "."; ) $data = get_part($imap, $uid, $mimetype, $ subStruct, $prefix .($index + 1)), if ($data) ( return $data; ) ) ) ) return false; ) function get_mime_type($structure) ( $primaryMimetype = array("TEXT", "MULTIPART", "MESSAGE", "APPLICATION", "AUDIO", "IMAGE", "VIDEO", "OTHER"); if ($structure ->subtype) ( return $primaryMimetype[(int)$structure->type] . "/" . $structure->subtype; ) return "TEXT/PLAIN"; )

Функція GetBody() отримує вміст електронної пошти, передаючи UID і з'єднання IMAP. Усередині функції ми закликаємо функцію get_part() з типом контенту як text/HTML. Звичайний текст повідомлення електронної пошти набагато легше читати. Таким чином, ми спочатку спробуємо знайти вміст HTML всередині електронної пошти.

Потім читаємо структуру електронної пошти за допомогою функції imap_fetchstructure() . Ми змінили функції бібліотеки, щоб використовувати UID, замість того, щоб передавати FT_UID постійно.

Тоді ми отримаємо тип MIME електронної пошти за допомогою функції get_mime_type() . Є вісім типів MIME, що повертаються цією функцією у вигляді цілих чисел:

  • 0 – TEXT
  • 1 – MULTIPART
  • 2 – MESSAGE
  • 3 – APPLICATION
  • 4 – AUDIO
  • 5 – IMAGE
  • 6 – VIDEO
  • 7 – OTHER

Ми перетворюємо повернення на реальний тип MIME рядки за допомогою масивів типів MIME.

Складові повідомлення можуть мати велику кількість підтипів, так що ми проходимо рекурсивно через всі підтипи, використовуючи частину номерів та отримання електронної пошти з використанням imap_fetchBody() , коли правильний знаходиться з використанням mime-type.

Потім ми використовуємо відповідну функцію декодування відповідно до кодування типу повідомлення і повертаємо зміст. Повний список доступних типів кодування:

  • 0 – 7BIT
  • 1 – 8BIT
  • 2 – BINARY
  • 3 – BASE64
  • 4 – QUOTED-PRINTABLE
  • 5 – OTHER

Висновок

Ми закінчили огляд основ з'єднання з сервером IMAP, список повідомлень всередині доступних папок, і закінчили читанням зміст повідомлення електронної пошти. На наступній сторінці запису буде розказано про функції, які можуть бути використані для реалізації додаткової функціональності поштового клієнта, наприклад, видалення повідомлень та обробка вкладень.

Днями мені прийшло завдання написати невеликий модуль на PHP, який дозволив би працювати з вхідною поштою. Трохи по гуглів я побачив що для цього завдання мені підходить один із протоколів POP3і IMAP.
Але вибір був очевидний що використати я буду IMAP тому що він є більш функціональний та сучасніший, протокол POP3.

Тепер мені треба було швиденько розібратися, як працювати з протоколами IMAP, як отримати листи з поштового сервера Yandex/Google.

Для зручнішої роботи я вибрав бібліотеку PhpImapоскільки вона може швидко і легко реалізує всі необхідні для мене завдання.

Підключення до поштового сервера.

Тепер коли ми визначилися з вибором протоколу та вибором бібліотеки, пробуватимемо підключатися до поштового сервера.

Для повноцінної роботи PHP з протоколом IMAP необхідно підключити розширення php_imap.dll/imap.soу файлі php.ini.

Для початку спробуємо підключитися до Yandex поштою так як у мене найменше виникло з нею проблем.

//Підключаємо бібліотеки include("/phpImap/Mailbox.php"); include("/phpImap/IncomingMail.php"); //Для зручності створимо константи для підключення до поштового сервера. define("MAIL_IMAP_SERVER", "imap.yandex.ru"); define("MAIL_IMAP_SERVER_PORT", 993); define("MAIL_IMAP_LOGIN", " "); define("MAIL_IMAP_PASS", "example_pass"); define("MAIL_IMAP_PATH", "(".MAIL_IMAP_SERVER.":".MAIL_IMAP_SERVER_PORT."/imap/ssl)INBOX"); $mailbox = новий PhpImap\Mailbox(MAIL_IMAP_PATH, MAIL_IMAP_LOGIN, MAIL_IMAP_PASS, __DIR__); try ( $mailbox->getImapStream(); ) catch (Exception $e) ( die($e->getMessage()); )

Як ми бачимо конструктор класу Mailboxприймає такі аргументи:

  • MAIL_IMAP_PATH- Містить адресу сервера (MAIL_IMAP_SERVER), порт підключення (MAIL_IMAP_SERVER_PORT), тип з'єднання (imap) і показуємо що з'єднання буде зашифровано (ssl). Після фігурних дужок вказуємо папку до якої підключатимемося, в даному випадку до вхідних повідомлень (INBOX).
  • MAIL_IMAP_LOGIN- Поштова скринька, яку будемо підключатися.
  • MAIL_IMAP_PASS- Пароль (найчастіше це пароль від поштової скриньки).
  • __DIR__- Це шлях до папки, в якій зберігатимуться вкладені файли та поштові повідомлення.

Після цього ми перевіримо, чи створилося наше підключення через метод getImapStream()якщо з якоїсь причини підключення не створиться, то програма викидає винятки з причиною не вдалого підключення.

Важливо врахувати, що в налаштуваннях Yandex пошти у вас може бути відключена можливість підключення по протоколу IMAP.

Тепер давайте порівняємо підключення до пошти Gmail.

Define("MAIL_IMAP_SERVER", "imap.gmail.com"); define("MAIL_IMAP_SERVER_PORT", 993); define("MAIL_IMAP_LOGIN", " "); define("MAIL_IMAP_PASS", "example_pass"); define("MAIL_IMAP_PATH", "(".MAIL_IMAP_SERVER.":".MAIL_IMAP_SERVER_PORT."/imap/ssl)INBOX");

Як ми бачимо, воно практично не відрізняється від попереднього підключення, але швидше за все у Вас спрацює виняток при підключенні до сервера.
Ця проблема пов'язана з тим, що в Gmail робота протоколу IMAP вимкнена за умовчанням. Увімкнути її можна в налаштуваннях у вкладці Пересилання та POP/IMAP у опції Доступ за протоколом IMAP ⇒ Увімкнути IMAP.

Після того, як ми включили роботу за протоколом IMAP, нам треба створити пароль додаток. Для того щоб його можна було створити, нам необхідно зробити двох факторну авторизацію для даного профілю. Після чого можна приступити до його створення. Коли ми створимо новий пароль для програми, нам необхідно його буде вписати в константу MAIL_IMAP_PASS для підключення до сервера.

Зверніть увагу, що при створенні пароля додатків у Вас може бути так і не вийде підключитися до сервера це зв'язково з тим, що цей пароль ще не застосовувався остаточно до сервісу Gmail зазвичай це займає 5-60 хвилин.

Вибірка даних

Після успішного підключення ми можемо виконати запит для отримання потових повідомлень із сервера. Для цього ми будемо використовувати метод searchMailBox(string $criteria)який по суті є обгорткою методу imap_search. Тут важливо зрозуміти що аргумент $criteria є певним критерієм пошуку потрібних нам повідомлень, сам метод повертає ідентифікатори елементів, які згодом нам знадобляться для отримання детальної інформації поштового повідомлення.

$mailsIds = $mailbox->searchMailBox("ALL");

Як Ви вже здогадалися, тут ми отримуємо всі повідомлення.
А тепер давайте спробуємо розібратися і з іншими не менш важливими критеріями пошуку:

// Всі повідомлення за 3 дні. $mailsIds = $mailbox->searchMailBox("SINCE "".date("d-M-Y",strtotime("-3 day"))."""); //Непрочитані повідомлення за 3 дні. $mailsIds = $mailbox->searchMailBox("UNSEEN SINCE" ".date("d-M-Y",strtotime("-3 day"))."""); //Пошук повідомлень з такою відповідністю в заголовку TEXT. $mailsIds = $mailbox->searchMailBox("TEXT "Новинне розсилання""); //Пошук повідомлень з такою відповідністю в заголовку BODY. $mailsIds = $mailbox->searchMailBox("BODY "Інформаційне повідомлення""); //Пошук по емейлу відправника. $mailsIds = $mailbox->searchMailBox("FROM""); //Отримати повідомлення за заголовком SUBJECT $mailsIds = $mailbox->searchMailBox("SUBJECT "Випущені оновлення для вашого телефону"");

Цей приклад добре відбиває основи використання критеріїв пошуку.

Отримання інформації

Тепер коли у нас є масив ідентифікаторів повідомлень, ми готові його обробити:

//Отримуємо ідентифікатор останнього повідомлення з масиву. $id = end($mailsIds); //Отримуємо екземпляр об'єкта класу IncomingMail, який містить інформацію про повідомлення. $mail = $mailbox->getMail($id); //Отримуємо файли, вкладені до цього повідомлення, якщо він є. $mail->getAttachments(); //Виводимо повідомлення. echo $mail->textHtml;

Ось ми й отримали повідомлення з нашого листа та його вкладення без жодних проблем.

Додаткові можливості.

У цій бібліотеці також є ряд корисних методів для зручнішої роботи з поштовими повідомленнями:

Зберігаємо повідомлення щодо його ід.

$mailbox->saveMail($id,$id.".eml");

Встановлюємо повідомлення як непрочитане за його ID.

$mailbox->markMailAsUnread($id);

Встановлюємо повідомлення як прочитане за його ID.

$mailbox->markMailAsRead($id);

Встановлюємо на повідомлення позначку на його id.

$mailbox->markMailAsImportant($id);

Видаляємо повідомлення за його ID.

Одним із можливих застосувань imap функцій є створення поштового демона, який керуватиме підпискою та відпискою користувачів від вашої поштової розсилки. Для реалізації цього завдання зазвичай у розсилках використовуються два методи. Перший припускає, що користувач повинен зайти на якусь сторінку та підтвердити свої дії, другий вимагає надсилання листа. Другий також вимагає, щоб скрипт-обробник регулярно запускався cron daemon?om. Через це він не такий популярний як перший спосіб.

Але, як можна помітити, найсерйозніші розсилки використовують другий спосіб. Тому, якщо у вас є можливість використання crond, скористайтеся ним.

Власне, розібратися у функціях не так складно. Людина, яка раніше працювала на РНР, легко зрозуміє, як з ними працювати. Деякі труднощі можуть виникнути з розбором заголовків листів, які оброблятимуть скрипт.

Алгоритм роботи самого скрипта вигадати нескладно. Демон встановлює з'єднання з поштовим сервером, і перевіряє наявність листів. Якщо листів немає, робота скрипта припиняється.
Якщо листи є, відбувається розбір заголовків першого листа. Проглядається поля from та subject. Якщо поле subject містить один із двох допустимих варіантів заголовка (підписка або відписка), то запис, якому відповідає значення поля from або стає активним (підтвердженим), або видаляється з таблиці. В обох випадках на адресу, вказану в полі від посилається відповідне повідомлення про дії скрипта. Після цього лист позначається видалення. Якщо subject не містить допустимих тем, надсилається повідомлення про помилку, і лист також позначається для видалення. Потім скрипт переходить до наступного листа.
Закінчивши розбір усіх листів, він очищає ящик.

Не втомлюватиму читача блок-схемами, тож одразу перейдемо до справи. Для відкриття ящика використовується функція imap_open. Оскільки РНР підтримує роботу з кількома протоколами, необхідно явно вказати, який протокол використовується для роботи зі скринькою. У нашому випадку це POP3 на 110 портах (стандарт). Привласнюємо результат виконання скрипта змінної $my_box.


Надалі ви побачите, що ця змінна буде використовуватися практично у всіх imap функціях. Далі перевіряємо ящик на наявність листів. Перевірку виконує функція imap_num_msg.

$n = imap_num_msg ($ my_box);

В результаті змінна $n міститиме кількість листів у ящику. Число це може бути або більше за нуль, або дорівнює йому (якщо ящик порожній).
Якщо листи є, то циклі while виконуємо розбір листів, послідовно збільшуючи номер листи на одиницю. Зверніть увагу, що перший лист в ящику буде мати номер 0, як і перший елемент масиву.
Для збільшення номера листа, привласнюємо змінною $m значення 0, а потім за умов виконання циклу збільшуємо її на одиницю $m++.

Для аналізу цікавих нас заголовків достатньо двох функцій: imap_header і imap_fetch_overview. Для виконання кожної з них, крім скриньки, необхідно вказувати номер листа. У нашому випадку, всередині циклу він дорівнюватиме змінній $m.

Imap_header повертає в результаті виконання об'єкт, що містить вичерпну інформацію про заголовок листа. Серед іншого, цей об'єкт містить масив від якого містить чотири значення. Це personal, adl, mailbox та host. Нас із них цікавлять лише mailbox та host. Підставляючи їх, ми отримаємо адресу, з якої було надіслано листа.


$h = $h -> from ;
a
foreach ($h as $k => $v ) (
$mailbox = $v -> mailbox;
$host = $v -> host;
$personal = $v -> personal;
$email = $mailbox. ? @¬. $host;

Imap_fetch_overview – дозволить нам дізнатися тему листа. Для цих же цілей можна було б використовувати і imap_header, але з ряду причин це іноді може не спрацювати. З масиву, який повертає ця функція, нам потрібне лише поле subject


foreach ($s як $k => $v ) (
$ subj = $ v -> subject ;
}

Подальші наші дії зводяться до того, щоб витягнути email з бази, і в разі наявності його там, помітити весь рядок із цим записом як «перевірений», або видалити. Припустимо, що після заповнення форми розсилки на сайті передплатнику надається статус 0, а після підтвердження підписки він змінюється на 1.

if ($subj == "SUBSCRIBE" ) (
mysql_query ( "UPDATE subscribe SET stat=1 WHERE email=$my_email");

}
mysql_query ( "DELETE FROM subscribe WHERE email = $my_email");
$del = imap_delete ($my_box, $m);
}
else (
$del = imap_delete ($my_box, $m);
}

як говорилося вище, після виконання всіх дій скрипт очищає ящик.


Дана найпростіша програма, лише демонстрація того, що на РНР можна писати не тільки сайти, що динамічно змінюються, а й сервіси, які користувачеві взагалі не видно. Звичайно, в частині написання скриптів для shell, рНР не застосовується, на відміну від свого конкурента Perl, але...

Лістинг усієї програми за винятком параметрів з'єднання з базою (db.php):

include "db.php";
$my_box = imap_open ("(you.pop.host/pop3:110)", "login", "password");
$n = imap_num_msg ($ my_box);
$m = 0;
$add_text = "

Дякуємо за підтвердження вашої підписки";
$add_sbj = "You added!" ;
$del_text = "

Вибачте, але ця поштова скринька використовується
тільки для адміністрування розсилки";
$err_sbj = "Error";
$headers = "From: Subscribe Robot

X-mailer: PHP4

Content-type: text/plain; charset=UTF-8
" ;
if($n! = 0) (
while($m ++< $n ) {
$ h = imap_header ($ my_box, $ m);
$s = imap_fetch_overview ($my_box, $m);
$h = $h -> from ;
foreach ($h as $k => $v ) (
$mailbox = $v -> mailbox;
$host = $v -> host;
$personal = $v -> personal;
$email = $mailbox. "@". $host;
$my_email = mysql_escape_string ($email);
}
foreach ($s як $k => $v ) (
$ subj = $ v -> subject ;
}
if ($subj == "SUBSCRIBE" ) (
mysql_query ( "UPDATE table SET stat=1 WHERE email=$my_email");
//print mysql_error();
$del = imap_delete ($my_box, $m);
mail ($email, $add_sbj, $add_text, $headers);
}
elseif ($subj == "UNSUBSCRIBE" ) (
mysql_query ( "DELETE FROM table WHERE email = $my_email");
$del = imap_delete ($my_box, $m);
mail ($email, $del_sbj, $del_text, $headers);
}
else (
$del = imap_delete ($open_box, $m);
mail ($email, $err_sbj, $err_text, $headers);
}
}
$clear = imap_expunge ($my_box);
}
?>


Електронна пошта - це найважливіший інструмент для обміну інформацією і якщо ви її використовуєте для роботи, то, напевно, стикалися з ситуацією: на пошту приходить лист, в якому містяться дані необхідні для обробки скрипом. Говорити ми будемо про Яндекс поштою – у цій статті я поділюся з вами, дорогі читачі, досвідом як дістати листи зі скриньки, так само ми розберемо варіант, коли в листі є вкладений файл – як його виявити та в результаті завантажити для подальших маніпуляцій над ним .

Сам я з цим завданням зіткнувся досить давно, і тоді за наявності малого досвіду роботи з поштовими програмами Яндекса витратив багато часу і нервів для досягнення необхідного результату. Перша моя помилка полягала в тому, що, як багато веб-розробників, я почав інтенсивно шукати схожі приклади в мережі, але не скористався самою довідкою (допомогою) Яндекс. Так, там є корисна інформація, хоча її і дуже мало, але вона досить важлива для написання такого роду скрипту (про це буде нижче). На той час потрібно було написати скрипт, суть якого зводилося: на Яндекс пошту замовника приходив лист із прайсом товарів у xls форматі раз на добу, його необхідно було обробити (розпарсувати та порівняти з даними з БД інтернет магазину та, залежно від результату, що- то оновити десь, вимкнути чи включити).

І перше, що ми зробимо перед написанням скрипту – це намітимо наш план дій, який складатиметься з дев'яти пунктів:

  1. Налаштуємо пошту отримання доступу через поштові протоколи;
  2. Намітимо саму структуру PHP програми та визначимося з кодуванням файлів;
  3. Ознайомимося з поштовим протоколом IMAP та його можливостями;
  4. Підключимося до Яндекс поштою через логін та пароль облікового запису та відстежимо помилки на цьому етапі;
  5. Обробимо шапку листа;
  6. Отримаємо та обробимо тіла листа;
  7. Отримаємо та збережемо вкладені файли;
  8. Візуалізуємо виконану роботу;
  9. Зробимо висновки.

Тема досить об'ємна, але я намагатимусь викласти все максимально компактно і зрозуміло. Мабуть, почнемо.

Налаштування пошти

Переходимо в свою пошту та заходимо в налаштування, як показано нижче на скріншоті:



Тепер ми потрапили в налаштування роботи пошти через протоколи IMAP та POP3:


Тут багато хто побачить картину як на зображення вище, але я стикався, і не раз, коли доступи відключені. Тому якщо у вас інші налаштування, ставимо галочки як на скріншоті, для нас головне дозволити доступ через протокол IMAP.

Структура програми та її кодування

У цьому прикладі ми не будемо вигадувати складну структуру програми, оскільки вона не потрібна, а додамо тільки те, що необхідно (я працюю в редакторі Sublime Text):


  • tmp – папка в яку завантажуватимемо вкладені файли з листа, якщо вони є;
  • .htaccess – налаштування серверної частини, якщо сервер apache;
  • functions.php – сюди додаватимемо наші функції;
  • main.css – файл стилів;
  • index.php - точка входу програми;

Кодування будемо використовувати UTF-8 і тому відразу заповнимо файл.htaccess наступними рядками:

AddDefaultCharset utf-8 AddCharset utf-8 * CharsetSourceEnc utf-8 CharsetDefault utf-8

Протокол IMAP

Повертаючись до першого пункту, видно, що працювати з поштою Яндекс можна також і через протокол POP3. То чому саме IMAP? З двох цих проток IMAP є більш новим і альтернативним POP3, отже, він має ряд переваг (їх можна вивчити, скориставшись вікіпедією), але в нашому випадку на вибір вплинуло тільки те, що він більш новий. Особисто я особливої ​​різниці не бачу, що використовуватиму під конкретне завдання отримання листа. Якщо з якоїсь причини вам потрібно використовувати протокол POP3, то всі функції, які застосовуються до IMAP, будуть працювати і для нього.

Підключаємось до Яндекс поштою за допомогою протоколу IMAP

Для того, щоб підключитися до пошти, нам потрібно знати три параметри: логін пошти, її пароль і адресу поштового сервера. Якщо з двома параметрами проблем немає, то другий можна знайти саме за допомогою Яндекс. Про це (виникла у мене проблемі) я вище і писав у мережі безліч прикладів, де третій параметр вказаний неправильно і, уявіть собі, що вже на стадії підключення виникають помилки – це, як мінімум, неприємно. Я не ходитиму навколо та навколо і відразу дам пряме посилання на сторінку Яндекс – налаштування поштових програм. Ось що нам потрібно для підключення:


Тепер можна переходити безпосередньо до самого коду:

Header("Content-Type: text/html; charset=utf-8"); error_reporting(0); require_once("functions.php"); $mail_login = "yandex_пошта"; $mail_password = "пароль_від_пошти"; $mail_imap = "(imap.yandex.ru:993/imap/ssl)"; // Список типів файлів $mail_filetypes = array("MSWORD"); $connection = imap_open($mail_imap, $mail_login, $mail_password); if(!$connection)( echo("Помилка з'єднання з поштою - ".$mail_login); exit; )else( $msg_num = imap_num_msg($connection); $mails_data = array(); for($i = 1; $ i<= $msg_num; $i++){ /* Работать с каждым письмом из IMAP-потока будем тут */ } } imap_close($connection);

Насамперед додатково вказуємо кодування UTF-8 за допомогою заголовка і відключаємо відображення помилок. Підключаємо файл functions.php і вказуємо налаштування, про які вище йшлося. У масиві $mail_filetypes прописуємо формати файлів, які нам потрібні. Так було вирішено зробити, щоб відсіяти непотрібне сміття та отримувати конкретні файли. З'єднання з поштою відбувається за допомогою функції imap_open(), яка при вдалому виконанні повертає IMAP-потік, а при невдалому - false (але якщо увімкнути відображення помилок, це не так). Завершуємо роботу з потоками за допомогою функції imap_close(), передавши їй індикатор з'єднання. Між двома функціями йде звичайний умовний оператор.

При вдалому з'єднанні за допомогою imap_num_msg() дізнаємося число листів поштою і додаємо масив, в який будемо поміщати всі необхідні дані з потоку. Далі слідує цикл, в якому оброблятиметься кожен лист за його номером (нумерація походить від 1) окремо.

Обробка шапки листа

Для отримання шапки листа необхідно скористатися функцією imap_header(), другим параметром якої є номер листа:

// Шапка листа $msg_header = imap_header($connection, $i);

На даному етапі ми отримаємо об'єкт, з якого і витягуватимемо потрібні нам дані, зберігаючи в масив $mails_data. Ось приклад одного з листів:

На цьому скріншоті видно, що всі дані дублюються, але це особливої ​​ролі не грає, тягнемо те, що зручніше. Набагато важливіше – кодування теми листа. Вона може бути будь-якою і цей момент треба контролювати. Така сама ситуація і з тілом листа і з вкладеними файлами.

$mails_data[$i]["time"] = time($msg_header->MailDate); $mails_data[$i]["date"] = $msg_header->MailDate; foreach($msg_header->to as $data)( $mails_data[$i]["to"] = $data->mailbox."@".$data->host; ) foreach($msg_header->from as $ data)( $mails_data[$i]["from"] = $data->mailbox."@".$data->host; )

Зберігаємо в нашому масиві: тимчасову мітку, дату отримання листа, email одержувача та відправника та переходимо до отримання теми листа. Для цього нам необхідно спочатку додати три функції до файлу functions.php:

Function check_utf8($charset)( if(strtolower($charset) != "utf-8")( return false; ) return true; ) function convert_to_utf8($in_charset, $str)( return iconv(strtolower($in_charset)), "utf-8", $str); ) function get_imap_title($str)( $mime = imap_mime_header_decode($str); $title = ""; foreach($mime as $key => $m)( if(!check_utf8) ($m->charset))( $title .= convert_to_utf8($m->charset, $m->text); )else( $title .= $m->text; ) ) return $title; )

Назви говорять і, я думаю, варто пояснити лише останню функцію. Вона приймає закодований рядок і за допомогою imap_mime_header_decode() декодує його, в результаті чого повертається масив об'єктів, у кожного з яких є дві властивості charset (кодування) та text (текст теми). Далі все просто: у циклі перевіряючи кодування, наводимо до UTF-8 і склеюємо тему в єдиний заголовок і повертаємо його.

Тепер повернемося до файлу index.php і витягнемо останній параметр:

$mails_data[$i]["title"] = get_imap_title($msg_header->subject);

На цьому обробка шапки листа буде завершено.

Працюємо з тілом листа

Продовжуємо поступово формувати наш масив із обробленими даними листа і тепер для отримання тіла нам необхідно скористатися двома функціями:

// Тіло листа $msg_structure = imap_fetchstructure($connection, $i); $msg_body = imap_fetchbody($connection, $i, 1);

У першій змінній $msg_structure знаходиться структура письма – це об'єкт, у якому можна знайти масу корисної інформації, приклад частини цього об'єкта представлений нижче:

Що важливо для вирішення нашого завдання:

  • type – первинний тип тіла листа, залежно від того, що до нас приходить на пошту, він може змінюватися від 0 до 7 (кожній цифрі радить свій вид контенту, який знаходиться в тілі листа);
  • encoding – кодування трансферу тіла, змінюється від 0 до 5 (0 – 7BIT, 1 – 8BIT, 2 – BINARY, 3 – BASE64, 4 – QUOTED-PRINTABLE, 5 – OTHER);
  • parts – масив частин письма, що відповідає структурі об'єкта рівнем вище.

Дещо докладніше розглянемо властивість parts. Перше, що треба сказати, це те, що в нульовому осередку цього масиву знаходиться інформація, що відповідає саме тексту листа, а починаючи з першого – вкладеним файлам. Також у кожному об'єкті вказується тип і в параметрах кодування в явному і неявному вигляді.

Структура листа може бути скільки завгодно вкладеною, принаймні у мене були випадки, коли доходило до чотирьох - п'яти рівнів, тому щоб її, як кажуть, роздраконити нам надалі потрібно написати рекурсивну функцію.

Друга функція imap_fetchbody() отримує певну частину листа, найчастіше в закодованому вигляді.

Тепер додамо змінну, в яку зберігатимемо оброблену версію тіла листа:

$body = "";

Повернемося до файлу functions.php і напишемо рекурсивну функцію:

Function recursive_search($structure)( $encoding = ""; if($structure->subtype == "HTML" || $structure->type == 0)( if($structure->parameters->attribute == " charset")( $charset = $structure->parameters->value; ) return array("encoding" => $structure->encoding, "charset" => strtolower($charset), "subtype" => $structure- >subtype); charset = $structure->parameters->value; ) return array("encoding" => $structure->encoding, "charset" => strtolower($charset), "subtype" => $structure->subtype); )

Функція recursive_search() приймає один параметр – структуру листа, де послідовно перевіряє властивості та дістає три параметри: encoding, charset, subtype. Точкою виходу з рекурсії є відсутність властивості parts з нульовим осередком. Більше пояснювати тут особливо нема чого, з коду я думаю зрозуміло, що і як відбувається.

Додамо ще одну функцію для переконвертації тіла листа, яка нам буде потрібна в подальшому:

Function structure_encoding($encoding, $msg_body)( switch((int) $encoding)( case 4: $body = imap_qprint($msg_body); break; case 3: $body = imap_base64($msg_body); break; case 2: $body = imap_binary($msg_body); break; case 1: $body = imap_8bit($msg_body); break; ;)

$recursive_data = recursive_search($msg_structure); if($recursive_data["encoding"] == 0 || $recursive_data["encoding"] == 1)( $body = $msg_body; ) if($recursive_data["encoding"] == 4)( $body = structure_encoding($recursive_data["encoding"], $msg_body); ) if($recursive_data["encoding"] == 3)( $body = structure_encoding($recursive_data["encoding"], $msg_body); recursive_data["encoding"] == 2)( $body = structure_encoding($recursive_data["encoding"], $msg_body); ) if(!check_utf8($recursive_data["charset"]))( $body = convert_to_utf8$ recursive_data["charset"], $msg_body);

Після того, як ми отримали дані з рекурсії, поступово перевіряємо кодування трансферу і залежно від цього викликаємо функцію structure_encoding() з відповідними параметрами. В останньому умовному операторі враховуємо те, що ми працюємо в UTF-8 і якщо після всіх маніпуляцій у нас вийде відмінне від кодування, перекодуємо.

Залишилося підвести межу:

$mails_data[$i]["body"] = base64_encode($body);

У тілі листа може бути, як і звичайний текст, і HTML розмітка зі своїми стилями. Кодуємо в BASE64, щоби при візуалізації не поїхала вже наша верстка.

Вкладені файли

Ось, плавно підбираємось до кінця написання нашої програми:

// Вкладені файли if(isset($msg_structure->parts))( for($j = 1, $f = 2; $j< count($msg_structure->parts); $j++, $f++)( if(in_array($msg_structure->parts[$j]->subtype, $mail_filetypes))( $mails_data[$i]["attachs"][$j]["type"] = $msg_structure->parts[$j]->subtype;$mails_data[$i]["attachs"][$j]["size"] = $msg_structure->parts[$j]->bytes; $i]["attachs"][$j]["name"] = get_imap_title($msg_structure->parts[$j]->parameters->value); $mails_data[$i]["attachs"][$ j]["file"] = structure_encoding($msg_structure->parts[$j]->encoding, imap_fetchbody($connection, $i, $f));file_put_contents("tmp/".iconv("utf-8") , "cp1251", $mails_data[$i]["attachs"][$j]["name"]), $mails_data[$i]["attachs"][$j]["file"]); )

Шматок, що відповідає за обробку вкладеного файлу набагато менше, а тепер чому саме так. Принцип роботи з файлом аналогічний роботі з тілом листа, тільки цей етап починаємо з його в масиві властивості parts. Не забуваймо відсівати непотрібні, звіряючись зі списком типів. За допомогою нехитрої функції file_put_contents() ми зберігаємо файл до себе на сервер в папку tmp.

Хочу побачити результат!

У процесі роботи у нас сформувався масив із даними $mails_data, і для візуалізації ми вже працюватимемо безпосередньо з ним. У цій статті я використав тестовий лист, який лежав у мене поштою, давайте подивимося, що в нас вийшло в результаті:


Ось якого виду приблизно повинен вийти масив, на жаль, довелося приховати зміст файлу з особистих причин. Тепер переходимо до нашої HTML розмітки:

Яндекс Пошта |<?php echo($mail_login);?>

Яндекс Пошта (Вхідні) |

Число листів:

листів немає
$mail):?>
Тимчасова мітка:
Дата:
Кому:
Від:
Тема:
Лист у base64:
Вкладені файли:
$attach):?>
Тип:
Розмір (в байтах):
Ім'я:
Тіло:

Стилі я не додаватиму тут, оскільки вони особливої ​​ролі не грають, в результаті:


А на сервері у папці tmp у вас з'явиться файл.

Висновок

Виконавши всі етапи зі статті, ви досягнете належного результату, але все не так просто, як може здатися - є підводні камені, які необхідно враховувати. При написанні скрипту під конкретне завдання необхідно стежити за кодуванням на всіх етапах, листи можуть йти з різних пошт, кожна з яких може мати свої нюанси. Так само важливим буде враховувати, що Яндекс пошта та їхня документація періодично оновлюється, тому можуть з'явитися різні підпункти для роботи з поштовими програмами. На цьому у мене все, сподіваюся вам стати в нагоді дана стаття при роботі з більш низькорівневим варіантом Яндекс пошти.

Не виходить отримати лист із вкладенням (
якщо надсилається пошта з файлом - будь-яким - то пропадає текст листа

Допоможіть будь ласка

Зрозуміло... якщо з яндексу на яндекс перекидати пошту, то все виходить...
типу розібрався
але ось чому інші файли крім ворда цей скрипт не приймає не зрозуміло ... там є рядок MSWORD поряд через кому поставив і пдф і жпг і пнг - читає і зберігає нормально тільки ворд .... як то так

© 2022 androidas.ru - Все про Android