Страницы

Поиск по вопросам

Показаны сообщения с ярлыком email. Показать все сообщения
Показаны сообщения с ярлыком email. Показать все сообщения

суббота, 11 апреля 2020 г.

Правильная настройка sendmail на сервер

#email #sendmail

                    
В общем есть сервер на Debian, там есть PHP и sendmail, отправка почты с PHP через
sendmail худо-бедно настроена.Письма с сервера отправляются от имени root@domain.com
по-умолчанию, если в mail() не указывать заголовок From.А если задать дополнительный
заголовок From, например info@domain.com, то письма приходят либо от root@domain.com,
либо от info@, но с совершенно каким-то левым доменом после @ (и естественно попадает
в спам).Получать почту на сервере не нужно, нужно только чтобы она нормально отправлялась.
Собственно 2 вопроса в итоге:как поменять пользователя (ящик) по-умолчанию (чтобы не
от root@domain.com отправлялись письма, а с ящика поприличнее на том же домене)?как
настроить отправку писем с любого ящика на этом домене (*@domain.com), то есть чтоб
они приходили от соответствующего ящика (info@domain.com, admin@domain.com)?     


Ответы

Ответ 1



Для начала надо почитать как вызывать функцию mail() в РНР. Дальше делаем такой вызов: mail('someuser@example.net', $subj, $mailbody, $additional_headers, '-f from@domain.com'); Здесь очень важен параметр -f - т.к. именно он задает от какого пользователя уйдет почта.

воскресенье, 15 марта 2020 г.

Долгие задачи в IIS сервер

#net #email #iis


Есть задача разработать сервис для рассылки почты, которым будут пользоваться остальные
сервисы/приложения/сайты внутри компании. Планирую сделать WEB-сервис. 
Схема примерно такая: 


есть паблик метод который принимает на вход что рассылать и кому.
метод получает пачку задач.
Метод порождает поток, который берет задачи и рассылает потихонечку. Сам метод продолжает
ожидать новых задач.


Есть минимум 2 проблемы:


До этого я всегда размещал сервисы в IIS. Однако, при наших объемах расылки, мы теоретически
можем получить задачу которая будет длится часы. Насколько я понимаю IIS может сам
прерывать задачи, которые длятся долгое время. Как мне этого избежать?
Сервис работает в контексте IIS. Думаю (но не уверен), что реально мой метод будет
не порождать потоки, а резервировать существующие внутри пула потоков IIS. Итого мы
можем в результате залочить все потоки и полностью заблокировать сервис.


Какой наиболее простой выход из этой ситуации? 
Возможно, мне стоит использовать SelfHosting WCF?
    


Ответы

Ответ 1



Нет, проблем с прерыванием задач не будет. Просто потому что у вас задача в отдельном потоке - IIS прерывает только те задачи, которые он запускал сам. Кстати, без отдельного потока он бы тоже не стал прибивать задачу - WCF служба неподвластна IIS, даже если использует его для активации. Если вы создаете поток через new Thread - то это будет именно отдельный поток, не имеющий никакого отношения к пулу IIS. В других случаях - да, такая проблема присутствует (кстати, у WCF и IIS тоже общие пулы). Способы "украсть" поток из общего пула: delegate.BeginInvoke ThreadPool.QueueUserWorkItem new Task BackgroundWorker Просто синхронная работа в операции WCF и еще куча более редких способов. Способы щадящей работы с общим пулом потоков: new Thread Использование асинхронных методов (они будут выполняться в общем пуле - но не будут занимать его надолго). На самом деле, проблемы вы ищите немного не там. Дело в том, что долгие операции рано или поздно захочется сделать еще и возобновляемыми, чтобы можно было, к примеру, выключить сервер для установки обновлений или для переезда на другой сервер - а потом продолжить все то, что не успело выполниться. Отдельную службу можно настроить, чтобы она запускалась автоматически. А сайт IIS - нет. Когда перед вами встанет такая задача - переход на SelfHosting WCF будет хорошим решением.

Ответ 2



Итого мы можем в результате залочить все потоки и полностью заблокировать сервис. Хотел бы немного осветить этот пункт. Вам совсем не нужно каждый раз создавать по потоку на каждый вызов. Я совсем не знаком с разработкой в контексте IIS, но уверен, что внутри можно реализовать некий сервис - главный управляющий поток (если он требуется) и N потоков-рабочих. Сервис представляет собой просто обертку над одной большой очередью заданий, которые потоки-рабочие берут по одной и выполняют, и когда появляется необходимость отправить пачку писем, принявший эти письма поток должен просто скормить их сервису, который просто положит их в конец очереди. После этого проблемы с перегрузкой сервера пропадают сами собой: количество потоков всегда фиксированное, в случае пустующей очереди они спят, сожрать весь процессор они тоже не могут, потому что большую часть времени ждут ответов по сети. Здесь начинаются проблемы с уже немного другим характером: следить надо не за загруженностью сервера, а за тем, чтобы очередь не имела возможности бесконечно расти. Поэтому метод приемки сообщений должен возвращать 200, если размер очереди + переданные сообщения не превышают лимит и 503, если существует опасность вылезти за разумные пределы очереди.

Ответ 3



IIS будет убивать ваш поток-обработчик при ресайкле пула приложений (app pool). Просто потому, что ресайкл аппула реализован перезапуска рабочего процесса IIS. Это может происходить, в зависимости от настроек, - по расписанию, по превышению памяти, вообще когда угодно. Например, при настройках по умолчанию appool будет убит через 20 минут неактивности. Вместе с вашим фоновым потоком. Хуже того, в некоторых случаях IIS будет запускать два рабочих процесса одновременно. Например, если включён overlapping recycling. Или если остановка старого аппула заняла больше времени, чем ожидалось (а это точно произойдёт, если вы запустить там долгий не-background поток). Даже при таких простых действиях, как редактирование конфига, поведение вашего "сервиса" будет полностью непредсказуемым. Хостить долгоживущие потоки в IIS - это плохая идея. Для долгоживущих потоков есть Windows Service (с self-hosted WCF в нём). Или, в случае стороннего хостинга - его замена в виде всяких webjobs.

суббота, 8 февраля 2020 г.

Функция mail(): трудности с кодировкой

#email #php #кириллица #utf_8 #кодировка


Всем доброго времени!  
Когда все было в windows-1251, все работало нормально. Иероглифы в письме появились,
после того как перевел все на utf-8.
Коды скриптов в utf-8, в html head meta http-equiv="Content-Type" content="text/html;
charset=utf-8".
Похожие темы гуглил, ничего пока не помогло. Использовать в поле From латиницу не
предлагать, т.к. нужна кириллица.
Когда письмо приходит на почту, то в общем списке писем, в поле от кого, кириллица
отображается корректно. Когда заходишь в само письмо, тот же текст в поле от кого,
корректно отображаются только латинские буквы и e-mail отправителя, кириллица выводится
иероглифами. Жирным выделено то, что смущает, в общем списке все нормально, значит,
я отправляю все правильно, но почему в самом письме все меняется?
Также пробовал варианты:

'subject' = '=?koi8-r?B?'.base64_encode(convert_cyr_string("Новое сообщение", "w","k")).'?=';  
'subject' = '=?utf-8?B?'.base64_encode(convert_cyr_string("Новое сообщение", "w","k")).'?=';  
'subject' = '=?koi8-r?B?'.base64_encode("Новое сообщение").'?=';  
'subject' = '=?utf-8?B?'.base64_encode("Новое сообщение").'?=';

На From никак не повлияло.
Код php:

 "tomail@site.ru",  
'subject' => "Новое сообщение",  
'message' => "

Текст сообщения

", 'headers' => "MIME-Version: 1.0\r\n"."Content-type: text/html; charset=utf-8\r\n"."From: Эта кириллица выводится иероглифами \r\n"); mail($mail['to'], $mail['subject'], $mail['message'], $mail['headers']);


Ответы

Ответ 1



Спасибо Stuf, последний комментарий натолкнул на ответ. Подстановки в subject никак не помогли, а вот конвертация только header все решила. Решил следующим образом: "tomail@site.ru", 'subject' => "Новое сообщение", 'message' => "

Текст сообщения

", 'headers' => "MIME-Version: 1.0\r\n"."Content-type: text/html; charset=utf-8\r\n"."From: Эта кириллица выводится иероглифами \r\n"); mail($mail['to'], $mail['subject'], $mail['message'], iconv ('utf-8', 'windows-1251', $mail['headers']));

суббота, 1 февраля 2020 г.

Функция mail() на сервере.

#email #php


Я пытаюсь добавить к регистрации проверку e-mail адреса. Добавил, но проверить работает
ли не могу. Сообщения на почту не приходят. Я прочитал на форумах, что нужно включить
функцию mail() на своем сервере. Как это сделать не знаю. Помогите. Устанавливал  локальный
сервер Apache.    


Ответы

Ответ 1



Поставьте себе любой SMTP сервер на комп. Настройте чтобы он пересылал письма через любую вашу почту. В настройках PHP поставьте его ип и порт, на который настроете и остальное, что надо и все. При обращении скрипт будет смотреть в настройках, куда обращаться и спокойно отсылать письма посредством вашего смтп сервера. P.S. что надо искать- [mail function] ; For Win32 only. SMTP = localhost smtp_port = 25 Вот тут и меняете порт, если настроите не на 25-й или ИП, если сервер на другой машине, в сети. P.P.S. Я, например, в свое время просто настраивал на СМТП сервер провайдера. У него всегда есть для своих абонентов такой сервер беспарольный, но с границей отправки 100 писем в день и 10 в час. Но для моих нужд хватало, ибо тоже делал просто проверку мыл и отсылку уведомлений.

Ответ 2



OS у вас какая? Vista. Могу посоветовать не использовать mail(), возьмите класс PHPMailer, настройте его на сервак yandex.ru по SMTP. В примерах к классу довольно толково описано, как настраивать этот класс.

Ответ 3



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

Ответ 4



В коде тестируй просто по условию !mail(), потом выкладывай на сервер и проверяй доходят ли письма.

среда, 22 января 2020 г.

Как правильно организовать email рассылку

#email #sendmail


Всем привет.
Есть база email порядка 30 000 000, нужно сделать рассылку. Подскажите, как правильно
сделать рассылку, чтобы не попасть в черный список, какие есть ограничения на отправку,
одним словом, как это правильно сделать?
    


Ответы

Ответ 1



В первом комментарии Вам дали правильные ссылки и их надо все изучить. Из личного опыта не спама, но самостоятельных коммерческих рассылок: нюансов очень много. Чисто технические нюансы: правильные и действительные PTR и SPF записи, настроенная DKIM-подпись, отсутствие (изначально) домена и ip адреса в блэк-листах, указание в письмах заголовка list-unsubscribe и Precedence: bulk (junk, list, list-unsubscribe и т. п.), отправка писем только через SMTP. Требования к домену тоже существуют: возраст от года, но чем старше, тем лучше, (Обяз.) Хост, осуществляющий рассылку, должен иметь постоянный IP-адрес с корректно настроенным обратным DNS-запросом. При этом регистрационные данные владельца домена должны быть актуальными и доступными публично по протоколу WHOIS. Для корректной идентификации доменное имя должно быть содержательным, а не являться автоматическим адресом наподобие x.y.z.w-in-addr-arpa или dsl-4-3-2-1.provider.net. Делать рассылки лучше с поддоменов (promo.example.com, info.example.com), соответственно использовать почтовые адреса отправителя с этих поддоменов. Домен должен иметь хорошую почтовую репутацию, например, можно перед основной рассылкой в течении недели разослать несколько десятков тысяч писем по небольшой надежной базе подписчиков, с малым процентом отказов ("прогреть" домен). К письмам тоже много требований: одно письмо - один получатель, в письме обязательно должна быть возможность отписаться от рассылки, в теле письма должен быть указан в явном виде email получателя (а-ля Вы получили письмо на электронный адрес example@example.com так как...), письма в формате html с соблюдением кодировки и MIME типов, нельзя использовать сокращатели ссылок. Очень желательно, чтобы письма были персонализированными, как тема письма, так и тело, а не полностью идентичными. Самые простые варианты - использовать имя получателя в письме (из базы подписчиков), разные приветствия, в зависимости от времени отправления письма, указание города или региона подписчика (если есть в базе) и т.п.. Не использовать в письмах "стоп слова" спам фильтров и изображения с форматом популярных рекламных баннеров. Очень важно: слать письма надо только с разрешения подписчика, на его проверенный email, не тот который он только указал, но и подтвердил, например переходом по ссылке отправленной на него! Почему это важно: после определенного количества отказов от рассылки (специфично для каждого почтового сервиса) все письма пойдут в спам, многие посчитали письмо спамом (а иногда людям проще ткнуть кнопку спам, чем отписываться от рассылки) все письма пойдут в спам, отправили подряд несколько писем на несуществующие, заблокированные ящики - получили бан на домен, пока перед саппортом почтовика не "изивинитесь". Перед запуском рассылки надо проверить качество отправляемого письма, я пользуюсь этим сервисом . Советую зарегистрироваться в Кабинете почтового мастера на распространенных почтовых сервисах: Яндекс , Мэйл, Google. Там Вы сможете смотреть подробную статистику рассылок, получать уведомления и рекомендации. Очень удобно и информативно. Лично мое мнение: если бы мне надо было сейчас разослать 30 млн писем, я бы делал это частями, например 100 разных рассылок по 300 тыс с десятка почтовых серверов.

суббота, 11 января 2020 г.

Отображение графиков в HTML письме

#javascript #html #email #canvas #svg


Есть рассылка по пользователям раз в неделю с информацией. Только эта информация
более наглядно будет смотреться в виде графика.
Вопрос: как отображать графики в HTML письме?

Iframe, JavaScript отпадает через неподражаемость в почтовых клиентах.

Есть мысль рендерить картинку, рабочий пример с сайта https://woody.aviasales.ru/graph.png?last_prices=14328,18610&average_price=14950

Они рендерят картинку по GET параметрах.

Как это сделать?

Есть проще альтернативы?
    


Ответы

Ответ 1



Такие графики обычно рисуются на php с помощью библиотеки GD http://php.net/manual/ru/book.image.php . Мы обращаемся по указанному адресу к скрипту, однако он на выходе отдает не html-документ, а изображение, сгенерированое на лету исходя из get-параметров. Стандартный скрипт выглядит примерно так: header("Content-type: image/png"); //сообщаем браузеру, что посылается картинка $string = $_GET['text']; $im = imagecreatefrompng("images/button1.png");//создаем картинку $orange = imagecolorallocate($im, 220, 210, 60); //что-то рисуем $px = (imagesx($im) - 7.5 * strlen($string)) / 2; imagestring($im, 3, $px, 9, $string, $orange); imagepng($im);//выводим изображение в буфер вывода imagedestroy($im);//особождаем память Там есть самые простые методы - рисование линии, дуги, эллипсы, заливки и т.д. Вообщем пайнт. Однако есть библиотеки, надстройки на GD, например, pchart или jpgraph упрощающие работу с графиками, возможно вам следует их попробовать для вашей задачи.

четверг, 2 января 2020 г.

Функция mail в php

#php #email


От кого придет сообщение, отправленное с помощью функции mail()? Нигде не могу найти
об этом информацию. 

В некоторых случаях отправителя дописывают в additional_headers, но ведь так можно
и что угодно дописать, хоть barackobama@whitehouse.gov
    


Ответы

Ответ 1



Если вы имеете ввиду отправителя письма, то оно будет таким, каким вы его укажите явно. Функция mail всего лишь передает вашему мейл серверу (скорее всего postfix) все данные, переданные вами в функцию. Это всего лишь инструмент, который делает запрос на почтовый сервер адресата, а что вы там укажите это на вашей совести. Самое плохое, что может случится это черные списки и спам листы. Не забудьте так же про DKIM и SPF

Ответ 2



Все зависит от настроек вашего сервера. Обычно в linux за это отвечает программа sendmail, а также от hostname. Если вы используете платный хостинг, то в личном кабинете можно настроить почтовые адреса и отправлять почту с них. Конечно вы можете в параметр from вставлять что угодно, но в заголовках письма все равно будет виден ваш hostname

Ответ 3



Пример - Дополнительные заголовки письма (additional headers) могут использоваться для указания кодировки письма, адреса отправителя, обратного адреса и множества других опций. Они должны быть разделены переводом строк: комбинацией "\r\n". Например, так:

Перевод строки в читабельный вид

#python #кодировка #email #перекодировка


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

=?windows-1251?Q?=EC=E5=ED=F2=2Etxt?=


Оригинал строки

мент.txt

    


Ответы

Ответ 1



Вам поможет модуль email.header import email.header a = "=?windows-1251?Q?=EC=E5=ED=F2=2Etxt?=" print email.header.decode_header(a) Приведеная вами строка закодирована согласно RFC2047. То есть формат строки такой: =?кодировка?признак типа кодирования?закодированная строка?= Признаков типа кодирования известно два Q и B. Соответственно они означают кодирование QuotedPrintable и Base64 соответственно. decode_header() принимает строку в формате RFC2047, распознает тип кодирования, декодирует и возвращает два параметра - декодированная строка и кодировка.

Ответ 2



import quopri a = '=EC=E5=ED=F2=2E' b = quopri.decodestring(a) print(b.decode('windows-1251'))

Google считает письма спамом

#php #email #sendmail #gmail #spam


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

    Delivered-To: *******@gmail.com
Received: by 10.25.208.143 with SMTP id h137csp471735lfg;
        Thu, 23 Feb 2017 06:55:46 -0800 (PST)
X-Received: by 10.28.236.93 with SMTP id k90mr2954531wmh.40.1487861746329;
        Thu, 23 Feb 2017 06:55:46 -0800 (PST)
Return-Path: 
Received: from *******.freedomain.thehost.com.ua ([176.114.3.106])
        by mx.google.com with ESMTPS id 196si6753159wmw.120.2017.02.23.06.55.45
        for 
        (version=TLS1_2 cipher=AES128-SHA bits=128/128);
        Thu, 23 Feb 2017 06:55:46 -0800 (PST)
Received-SPF: softfail (google.com: domain of transitioning no-reply@mysite.net does
not designate 176.114.3.106 as permitted sender) client-ip=176.114.3.106;
Authentication-Results: mx.google.com;
       spf=softfail (google.com: domain of transitioning no-reply@mysite.net does
not designate 176.114.3.106 as permitted sender) smtp.mailfrom=no-reply@mysite.net
Message-ID: <58aef7f2.cd161c0a.52af6.98a5SMTPIN_ADDED_BROKEN@mx.google.com>
X-Google-Original-Message-ID: <172562218.20170223165545mysite.net>
Received: from *********.freedomain.thehost.com.ua ([176.114.3.106] helo=mysite.net)
by *********.freedomain.thehost.com.ua with esmtpa (Exim 4.82) (envelope-from )
id 1cguo5-0002y0-GN for myEmailName@gmail.com; Thu, 23 Feb 2017 16:55:45 +0200
Date: Thu, 23 Feb 2017 16:55:45 +0200
From: "Робот сервера mysite.net" 
X-Mailer: The Bat! (v3.99.3) Professional
Reply-To: "Робот сервера mysite.net" 
X-Priority: 3 (Normal)
To: "myEmailName" 
Subject: Создание аккаунта(mysite.net)
MIME-Version: 1.0
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: 8bit


        
        
        
        
        
        

Добро пожаловать на mysite.net

Ваш аккаунт "LADUSHKA" создан. Для завершения регистрации Вам необходимо в течение 3 дней перейти по ссылке. https://mysite.net/index.php?id=verification&hash=065f5117caeacc8642434e0024af61e0


Ответы

Ответ 1



Received-SPF: softfail говорит о том, что не настроен SPF. Добавьте в файл DNS зоны(mysite.net), запись: mysite.net. IN TXT "v=spf1 +a +mx -all" Также стоит настроить DKIM. Настройка для Ubuntu сервера: sudo apt update sudo apt install opendkim opendkim-tools vim /etc/opendkim.conf Правим конфиг: Syslog yes UMask 002 Domain mysite.net KeyFile /etc/mail/dkim.key Selector mail SubDomains yes OversignHeaders From Socket inet:8891@localhost Генерируем ключи: opendkim-genkey --domain=mysite.net --selector=mail --verbose sudo mv mail.private /etc/mail/dkim.key sudo chown root:root /etc/mail/dkim.key sudo chmod 400 /etc/mail/dkim.key cat mail.txt # Публичный ключ для записи домена Настраиваем sendmail: cd /etc/mail echo "INPUT_MAIL_FILTER(`opendkim', `S=inet:8891@localhost')dnl" >> sendmail.mc m4 sendmail.mc > sendmail.cf service opendkim restart service sendmail restart Добавляем TXT запись mail._domainkey: v=DKIM1; g=*; k=rsa; p=MIGfMA0GCSqGSIb3D... Указанная в Content-type кодировка не относится к заголовкам письма. Как следствие Subject нужно кодировать. На php это делается так: $subject = mb_encode_mimeheader($subject, 'UTF-8', 'B', "\r\n", strlen('Subject: '));

Ответ 2



Google может посчитать письмо спамом по множеству причин, но вам следует обратить внимание на это: Received-SPF: softfail (google.com: domain of transitioning no-reply@mysite.net does not designate 176.114.3.106 as permitted sender) Скорее всего у вас в качестве адреса отправителя указан адрес, доменное имя которого не соответствует IP домена, с которого отправляется почта. Попробуйте указать реальный почтовый ящик, IP адрес домена которого является 176.114.3.106.

Ответ 3



Это самое важное, пропишите в DNS своего домена TXT SPF запись примерно следующего содержания: mysite.net. IN TXT "v=spf1 +a +mx +ip4:176.114.3.106 -all". Так же почитайте по поводу DKIM Если ваш хостер позволяет менять PTR запись для вашего ip поставьте в нее имя вашего домена с которого отправляется почта. Т.е. что бы PTR запись для ip давала такое же имя для которого A запись указывает на этот ip. Сейчас там стоит ....freedomain.thehost.com.ua который например спамассасину не нравится видимо из за наличия слова free а адресе. Текущее состояние проверяется просто nslookup ip-с-которого-шлется-почта В вашем письме нет Message-ID, его добавляет уже гугл при получении. Должно быть уникальное Message-ID оканчивающееся на @ваш-домен. Обычно это сам делает какой нибудь sendmail на вашей машине, через который вы по идее должны отправлять почту. Напишите каким нибудь почтовым клиентом письмо с такой же темой, как вы отправляете и посмотрите как кодируется заголовок. Сейчас у вас там просто текст, а должно быть что то вроде Subject: =?UTF-8?B?0KHQvtC30LTQsNC90LjQtSDQsNC60LrQsNGD0L3RgtCwKG15c2l0ZS5u?= =?UTF-8?B?ZXQp?= Русские буквы открытым текстом в заголовках письма нарушают стандарты. Напишите побольше текста. В несколько строк. Сейчас spamassasin говорит "Message body is only a URI in one line of text or for an image"

понедельник, 30 декабря 2019 г.

Проверка e-mail на существование

#php #email


Как можно определить e-mail на существование на php? 
Можно конечно через этот сервис curl запросы отправлять. Но хотелось бы узнать, как
они это сделали.    


Ответы

Ответ 1



в ТЕОРИИ сделать можно, но не везде. по поводу гугла: telnet gmail-smtp-in.l.google.com 25 helo example.com mail from: rcpt to: 550-5.1.1 The email account that you tried to reach does not exist. Please try 550-5.1.1 double-checking the recipient's email address for typos or 550-5.1.1 unnecessary spaces. Learn more at 550 5.1.1 http://mail.google.com/support/bin/answer.py?answer=6596 а если пользователь существует, то будет ответ: 250 2.1.5 OK вот более полный расписанный ответ Все это вполне может работать и для других серверов.

Ответ 2



Не уверен, что это программируется на ПХП. Видимо наиболее реально попробовать соединиться с сервером (узнав по MX в DNS его адрес) по SMTP и "начать отправку почты", послать в итоге RCPT TO: проверяемый@адрес и если ответ положительный, то можно предполагать, что такой e-mail существует.

Ответ 3



см. комментарий. я это нашел! На хабре расписано что, где и как. В том же топике хабра есть коммент. Можно и самому придумать какой-нибудь способ)

Ответ 4



этого сделать нельзя в принципе провалидировать правильность написания адреса согласно стандарту - это пожалуйста

Ответ 5



function isEmail ($email) { return preg_match("/^([a-z0-9_-]+\.)*[a-z0-9_-]+@[a-z0-9_-]+(\.[a-z0-9_-]+)*\.[a-z]{2,6}$/i",$email); }

воскресенье, 29 декабря 2019 г.

Как отправить сообщение на почту из командной строки линукса

#linux #email


Собственно, как отправить сообщение на почту из командной строки линукса?    


Ответы

Ответ 1



Самый простой вариант: echo "Test" | sendmail user@mail.com Если нужны "правильные" заголовки в письме, то отправляем так: echo "From: SENDER " > /tmp/temp echo "To: USER " >> /tmp/temp echo "Subject: TEST MESSAGE" >> /tmp/temp echo "BODY MESSAGE" >> /tmp/temp cat /tmp/temp | sendmail user@mail.com

Ответ 2



Можно установить утилиту sendmail. sudo apt-get install sendmail И вызвать команду. sendmail -f from@yandex.ru -m "message" -t to@gmail.com -s smtp.yandex.ru:587 -xu from@yandex.ru -xp password -a /attached_file.txt

Ответ 3



sendmail -bs Далее SMTP протокол Вообще этот способ на любителя...

Ответ 4



# mail -s "Hello" login@domain.com ^D

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

#php #email #почта


Пишу скрипт отправки почты с вложением. 

$file = "act.pdf"; // файл
$mailTo = "rumyancevaa@afanasy.ru"; // кому
$from = "rumyancevaa@afanasy.ru"; // от кого
$subject = "Общественная приемная"; // тема письма
$message = "Контактный телефон обратившегося "; // текст письма
$r = sendMailAttachment($mailTo, $from, $subject, $message, $file); // отправка письма
c вложением
echo ($r)?'

Ваша заявка отправлена! Скоро мы ее рассмотрим и позвоним вам!

':'Ошибка. Письмо не отправлено!'; //$r = sendMailAttachment($mailTo, $from, $subject, $message); // отправка письма без вложения //echo ($r)?'Письмо отправлено':'Ошибка. Письмо не отправлено!'; function sendMailAttachment($mailTo, $from, $subject, $message, $file = false){ $separator = "---"; // разделитель в письме // Заголовки для письма $headers = "MIME-Version: 1.0\r\n"; $headers .= "From: $from\nReply-To: $from\n"; // задаем от кого письмо $headers .= "Content-Type: multipart/mixed; boundary=\"$separator\""; // в заголовке указываем разделитель // если письмо с вложением if($file){ $bodyMail = "--$separator\n"; // начало тела письма, выводим разделитель $bodyMail .= "Content-Type:text/html; charset=\"utf-8\"\n"; // кодировка письма $bodyMail .= "Content-Transfer-Encoding: 7bit\n\n"; // задаем конвертацию письма $bodyMail .= $message."\n"; // добавляем текст письма $bodyMail .= "--$separator\n"; $fileRead = fopen($file, "r"); // открываем файл $contentFile = fread($fileRead, filesize($file)); // считываем его до конца fclose($fileRead); // закрываем файл $bodyMail .= "Content-Type: application/octet-stream; name==?utf-8?B?".base64_encode(basename($file))."?=\n"; $bodyMail .= "Content-Transfer-Encoding: base64\n"; // кодировка файла $bodyMail .= "Content-Disposition: attachment; filename==?utf-8?B?".base64_encode(basename($file))."?=\n\n"; $bodyMail .= chunk_split(base64_encode($contentFile))."\n"; // кодируем и прикрепляем файл $bodyMail .= "--".$separator ."--\n"; // письмо без вложения }else{ $bodyMail = $message; } $result = mail($mailTo, $subject, $bodyMail, $headers); // отправка письма return $result; } Каким образом можно добавить второе вложение из input type = "file" на форме?


Ответы

Ответ 1



Три простых шага для решения данной проблемы: Посмотреть на календарь и уточнить, какой сейчас век на дворе. Аккуратно выделить этот код, и нажать клавишу Del Скачать phpmailer Забыть все эти кустарные ковыряния как страшный сон. В итоге код должен получиться примерно таким: require 'PHPMailerAutoload.php'; $mail = new PHPMailer; $mail->setFrom('from@example.com', 'First Last'); $mail->addAddress('whoto@example.com', 'John Doe'); $mail->Subject = 'PHPMailer file sender'; $mail->msgHTML("My message body"); // Attach uploaded files $mail->addAttachment($filename1); $mail->addAttachment($filename2); $r = $mail->send(); следует понимать, что отправка почты - это не просто копирование в свой скрипт каких-то определенных сочетаний символов, к оторые случайно сработали в прошлом веке у автора какой-либо допотопной статьи. Это гораздо более сложный процесс, который включает множество нюансов. И поэтому отправку почты надо не лепить вручную из подручных средств на ходу, а доверить проверенному и отлаженному решению.

Ответ 2



В функцию бросайте массив $_FILES и далее его разбираете: function sendMailAttachment($mailTo, $From, $subject_text, $message, $_FILES){ $to = $mailTo; $EOL = "\r\n"; // ограничитель строк, некоторые почтовые сервера требуют \n - подобрать опытным путём $boundary = "--".md5(uniqid(time())); // любая строка, которой не будет ниже в потоке данных. $subject= '=?utf-8?B?' . base64_encode($subject_text) . '?='; $headers = "MIME-Version: 1.0;$EOL"; $headers .= "Content-Type: multipart/mixed; boundary=\"$boundary\"$EOL"; $headers .= "From: $From\nReply-To: $From\n"; $multipart = "--$boundary$EOL"; $multipart .= "Content-Type: text/html; charset=utf-8$EOL"; $multipart .= "Content-Transfer-Encoding: base64$EOL"; $multipart .= $EOL; // раздел между заголовками и телом html-части $multipart .= chunk_split(base64_encode($message)); #начало вставки файлов foreach($_FILES["file"]["name"] as $key => $value){ $filename = $_FILES["file"]["tmp_name"][$key]; $file = fopen($filename, "rb"); $data = fread($file, filesize( $filename ) ); fclose($file); $NameFile = $_FILES["file"]["name"][$key]; // в этой переменной надо сформировать имя файла (без всякого пути); $File = $data; $multipart .= "$EOL--$boundary$EOL"; $multipart .= "Content-Type: application/octet-stream; name=\"$NameFile\"$EOL"; $multipart .= "Content-Transfer-Encoding: base64$EOL"; $multipart .= "Content-Disposition: attachment; filename=\"$NameFile\"$EOL"; $multipart .= $EOL; // раздел между заголовками и телом прикрепленного файла $multipart .= chunk_split(base64_encode($File)); } #>>конец вставки файлов $multipart .= "$EOL--$boundary--$EOL"; if(!mail($to, $subject, $multipart, $headers)){ echo 'Письмо не отправлено'; } //Отправляем письмо else{ echo 'Письмо отправлено'; } } P.S.: код проверен на работоспособность.

Ответ 3



$_FILES - глобальный массив, доступен везде, передавать в функцию не обязательно. Способ с PhpMailer - лучшее решение.

пятница, 27 декабря 2019 г.

HTML теги в присылаемом письме

#html #ubuntu #email #postfix


Отправляю письмо в Ubuntu 12.04 (postfix) при помощи команды:

mail -s "Test" adress@domain.ru < mailbody.html


Содержимое mailbody.html:



        
                
        
        
                Заголовок
                Текст письма.
        



Присылаемое письмо:



        
                 
         
         
                Заголовок 
                Текст письма. 
        



Почему отображаются теги HTML, вместо форматирования?
    


Ответы

Ответ 1



Из комментария пользователя @Sergey: Чтобы отображался форматированный по правилам HTML текст, письмо должно содержать служебный заголовок, в котором указан mime-тип содержимого (text/html). И это не тег meta из HTML. Команда mail на разных системах имеет разные возможности для добавления заголовков. Попробуйте mail -s "Test" adress@domain.ru -a "Content-type: text/html" < mailbody.html.

среда, 25 декабря 2019 г.

Отправка email (java)

#java #email


Я пытаюсь отправить email с помощью следующего кода:

  try {
        String mailFrom = "sender@mail.ru";
        String pass = "pass";
        String mailTo = "recipient@gmail.com";

        java.util.Properties props = new Properties();
        props.put("mail.smtp.host", "smtp.mail.ru");
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.port", "587"); 
        props.put("mail.smtp.starttls.enable", "true");

        props.put("mail.smtp.connectiontimeout", "60000"); // 60 seconds
        props.put("mail.smtp.timeout", "60000");

        Session session = Session.getInstance(props, new Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
                return (new PasswordAuthentication(mailFrom, pass));
            }
        });
        Message msg = new MimeMessage(session);
        InternetAddress addressFrom = new InternetAddress(mailFrom);
        msg.setFrom(addressFrom);
        InternetAddress addressTo = new InternetAddress(mailTo);
        msg.setRecipient(Message.RecipientType.TO, addressTo);
        msg.setSubject("testemail");
        Transport.send(msg);
   } catch (Throwable e) {
        System.err.println("Exception : " + e.toString());
   } 


но получаю ошибку:


  Exception : javax.mail.MessagingException: Could not convert socket to
  TLS;
  nested exception is:  javax.net.ssl.SSLHandshakeException:
  sun.security.validator.ValidatorException: PKIX path building failed:
  sun.security.provider.certpath.SunCertPathBuilderException: 
  unable to find valid certification path to requested target


При этом я добавила ssl-сертификат mail.ru в хранилище сертификатов JVM, и он был
успешно добавлен. 

Если же я добавляю в сессию следующее свойство:

props.put("mail.smtp.ssl.trust", "*");


то по прошествии минуты (по истечении установленного таймаута) получаю другую ошибку:


  Exception : javax.mail.MessagingException: Exception reading response;
  nested exception is:  java.net.SocketTimeoutException: Read timed out


Как исправить это и всё-таки отправить email?
    


Ответы

Ответ 1



Проблема была в том, что я пыталась отправить пустое сообщение, без тела (почтовый клиент обычно разрешает посылать такие сообщения, но в моём случае это привело к ошибке). Это выяснилось после того, как я добавила в сессию свойство props.put("mail.debug", "true"); После этого в отладочной информации я увидела причину ошибки: 354 Enter message, ending with "." on a line by itself DEBUG SMTP: MessagingException while sending, THROW: javax.mail.MessagingException: No MimeMessage content После получения этого описания ошибки я добавила тело сообщения: msg.setText("Test message!"); и email был успешно отправлен.

воскресенье, 22 декабря 2019 г.

Почему SmtpClient не отправляет письмо и не выдает исключение?

#c_sharp #wpf #email #mailru


При запуске данного кода:

MailMessage mail = new MailMessage();
mail.From = new MailAddress(senderBox.Text);
mail.To.Add(recipientBox.Text);
mail.Subject = subjectBox.Text;
mail.Body = bodyBox.Text;

SmtpClient SmtpServer = new SmtpClient("smtp.mail.ru");
SmtpServer.Port = 465;
SmtpServer.Credentials = new NetworkCredential(senderBox.Text, passwordBox.Password);
SmtpServer.EnableSsl = true;

try
{
    SmtpServer.Send(mail);
}
catch (Exception exc)
{
    MessageBox.Show(exc.Message);
}


Код покидает функцию после строки SmtpServer.Send(mail);, но письмо не отправляется
и код не входит в catch-блок. Чем можно объяснить такое поведение?
UPD:
проблема была в порте.Попробовал 587-все нормально работает
    


Ответы

Ответ 1



Для диагностики, чтобы понять что происходит, можно включить следующий блок в раздел в файл app.config Тогда можно будет увидеть и понять отправилось Ваше сообщение на smtp сервер или нет и что именно происходит.

Ответ 2



SMTP сервер mail.ru не смотря на то что работает через SSL но при этом использует 25 порт, вот такой вот парадокс, потратил пол-дня пока разобрался

Ответ 3



Метод Send не гарантирует 100% отправки сообщения. Этот метод только добавляет ваше письмо в очередь на отправку на SMTP сервере, а дальше уже сервер сам решает отправлять его или нет. Проверьте сервер. На том же mail.ru стоят фильтры антиспама - проверьте, что письмо не попало в них. Если ничего не выйдет - напишите в саппорт или смените SMTP сервер.

Ответ 4



Вот мой работающий код (ранее тоже мучался с этим вопросом) private Task SendEmailAsync(IdentityMessage message) { string email_address = "blala@blala.ru"; SmtpClient smtp = new SmtpClient("smtp.mail.ru", 25); smtp.Credentials = new NetworkCredential(email_address, "blala"); smtp.EnableSsl = true; smtp.Timeout = 20000; //20s MailMessage mailMessage = new MailMessage(email_address, message.Destination, message.Subject, message.Body); try { //smtp.SendAsync(mailMessage, 1); smtp.Send(mailMessage); } catch (Exception ex) { Debug.WriteLine($"Произошла ошибка при отправке email: {ex.Message}"); Task.FromException(ex); } return Task.FromResult(0); }

Отправляя письма через форму на сайте, письма приходят с неверной кодировкой

#email #php #sendmail


Здравствуйте! 
Написал простенький скрипт обратной формы на php + jquary.
Сам скрипт с функцией mail():
";   
echo "Ваш контактный телефон        :".$email."
"; echo "Время и дата :".$sug."
"; echo "Ваш запрос отправлен. Спасибо вам за ваш интерес к нашей компании!"; $from = 'test@mail.ru'; $emailTo = 'test@mail.ru'; $subject = '=?UTF-8?B?'.base64_encode('Запрос прайс листа с сайта: test').'?='; $headers = 'Content-type: text/plain; charset=utf-8'; $headers .= "From: ". $from ." <". $from ."> \r\n"; $body = "Ф.И.О. контактного лица: $name \n\nКонтактный телефон клиента: $email \n\nВремя и дата удобное для звонка ему:\n $sug"; $headers = 'C сайта: test <'.$emailTo.'>' . "\r\n" . 'Отправитель: ' . $name . "\r\n" ; $headers .= "Date: ". date('D, d M Y h:i:s O') ."\r\n"; mail($emailTo, $subject, $body, $headers, '-f'. $from ); $emailSent = true; }?> В данном скрипте проблему с заголовком письма решил, если письмо отправляю на локальном сервере в denwer и читаю их в Thunderbird то с кодировкой проблем нет, как только выложил его на виртуальный сервак и отправил письмо на почтовый ящик размещенный на mail.ru, появляются крокозябры: C я│п╟п╧я┌п╟: test п·я┌п©я─п╟п╡п╦я┌п╣п╩я▄: я┌п╣я│я┌п╦я─п╬п╡п╟п╫п╦п╣ Date: Mon, 24 Jun 2013 11:03:16 +0400 п╓.п≤.п·. п╨п╬п╫я┌п╟п╨я┌п╫п╬пЁп╬ п╩п╦я├п╟: я┌п╣я│я┌п╦я─п╬п╡п╟п╫п╦п╣ п п╬п╫я┌п╟п╨я┌п╫я▀п╧ я┌п╣п╩п╣я└п╬п╫ п╨п╩п╦п╣п╫я┌п╟: я┌п╣я│я┌п╦я─п╬п╡п╟п╫п╦п╣ п▓я─п╣п╪я▐ п╦ п╢п╟я┌п╟ я┐п╢п╬п╠п╫п╬п╣ п╢п╩я▐ п╥п╡п╬п╫п╨п╟ п╣п╪я┐: я┌п╣я│я┌п╦я─п╬п╡п╟п╫п╦п╣ Тема письма отображается верно. Прошу помощи разобраться в данной проблеме.


Ответы

Ответ 1



Ну как бы все пользуются для почты http://phpmailer.worxware.com/. Но в вашем случаи есть прям в документации ответ http://php.net/manual/en/function.mail.php : function mail_utf8($to, $subject = '(No subject)', $message = '', $from) { $header = 'MIME-Version: 1.0' . "\n" . 'Content-type: text/plain; charset=UTF-8' . "\n" . 'From: Yourname <' . $from . ">\n"; mail($to, '=?UTF-8?B?'.base64_encode($subject).'?=', $message, $header); }

Ответ 2



У меня тоже тело письма отправляло кракозябрами. Декодером лебедева проверил - оказалось что кракозябры в кодировке KOI8-R. Помог код преобразования KOI8-R в UTF-8. Сама страничка у меня в кодировке UTF-8. $mes = "Номер телефона: $tele"; /*Тело письма, которое неправильно отображалось*/ $in_charset = "KOI8-R"; $out_charset = "UTF-8"; iconv ($in_charset, $out_charset, $mes); /*Преобразуем*/ $send = mail($address, $sub, $mes,"Content-type:text/plain; charset=UTF-8" );

суббота, 21 декабря 2019 г.

Отправка email. Не отправляется письмо с кириллицей

#python #python_3x #email #smtplib


Цель: Нужно отослать письмо на пошту. В письме есть кириллические символы.

Проблема: скрипт работает с латинскими символами, но не работает з кириллицей

Скрипт:

import smtplib
TEXT = "Кириллица \n"\
        "Кириллица\n"

TO = 'xxxxxx@gmail.com'
SUBJECT = 'xxxx'
# Gmail Sign In
gmail_sender = 'xxxx@gmail.com'
gmail_passwd = 'xxxxxx'
server = smtplib.SMTP('smtp.gmail.com', 587)
server.ehlo()
server.starttls()
server.login(gmail_sender, gmail_passwd)

BODY = '\r\n'.join(['To: %s' % TO,
                    'From: %s' % gmail_sender,
                    'Subject: %s' % SUBJECT,
                    '', TEXT])
try:
    server.sendmail(gmail_sender, [TO], BODY)
    print('email sent')
except:
    print('error sending mail')
server.quit()


Ошибка: 

Traceback (most recent call last):
  File "C:/Users/babai/PycharmProjects/test/mail.py", line 47, in 
    server.sendmail(gmail_sender, [TO], BODY)
  File "C:\Program Files (x86)\Python36-32\lib\smtplib.py", line 854, in sendmail
    msg = _fix_eols(msg).encode('ascii')
UnicodeEncodeError: 'ascii' codec can't encode characters in position 63-74: ordinal
not in range(128)


На сколько я понимаю проблема в кодировке. Тоесть модуль smtplib работает только
с ANSII ??
    


Ответы

Ответ 1



Проблема решена с помощю MIMEText Решение найдено вот здесь https://ru.stackoverflow.com/a/369479/237582 Спасибо jfs # -*- coding: utf-8 -*- """Send email via smtp_host.""" import smtplib from email.mime.text import MIMEText from email.header import Header smtp_host = 'smtp.gmail.com' # yahoo login = "xxxxxx@gmail.com" password = "xxxxxxx" recipients_emails = "xxxxxx@gmail.com" msg = MIMEText('Спасибо', 'plain', 'utf-8') msg['Subject'] = Header('subject…', 'utf-8') msg['From'] = login msg['To'] = recipients_emails s = smtplib.SMTP(smtp_host, 587, timeout=10) s.set_debuglevel(1) try: s.starttls() s.login(login, password) s.sendmail(msg['From'], recipients_emails, msg.as_string()) finally: print(msg) s.quit()

воскресенье, 15 декабря 2019 г.

Рассылка по e-mail в высоконагруженном проекте

#рассылка #регистрация #email


Добрый день, задача следующая:
Имеется сайт на котором проходит порядка 5 регистраций в секунду.
Всем зарегистрировавшимся необходимо отправить сообщение по e-mail с ссылкой подтверждения.
В наличии: свой SMTP-сервер, PHP, MySQL
Мое виденье данного процесса следующие:
Обрабатываем регистрации пользователей, заносим в БД ключ подтверждения, наряду с
остальными данными пользователя.
Потом раз к примеру в секунд 10 выберем свежеиспечённых юзеров по наличию этого ключа,
И рассылаем сообщения по SMTP (по сокету, перечисляя в запросе получателей).
При подтверждении ключ затираем, registration is completed!
Хотелось бы услышать мнения и рекомендации для оптимизации данного подхода, а так
же возможные пути решения задачи.    


Ответы

Ответ 1



Я обычно делаю три поля: КлючПотверждения, НовыйПароль, БылоЛиПисьмо. Объясняю зачем. Для нового пользователя в поле Пароль ставится "", заполняется НовыйПароль, БылоЛиПисьмо* = 0. Отправлялка делает запрос везде, где БылоЛиПисьмо = 0. И для них сразу делает апдейт БылоЛиПисьмо = 1. После успешной отправки письма, делается БылоЛиПисьмо = 2. Если была ошибка отправки - БылоЛиПисьмо = 3, или письмо вернулось с отлупом БылоЛиПисьмо = 4 (мониторится по РОРу). Эта таблица периодическим кем-то мониторится, чистится. БылоЛиПисьмо == 3 раз в несколько часов отправляется, пока не пройдут сутки с момент регистрации, потом ставится как отлуп. При нажатии ссылки с ключем -> Пароль = НовыйПароль. КлючПотверждения = пусто, НовыйПароль = пусто. При сбросе пароля заполняется НовыйПароль и КлючПотверждения. Если в БД Пароль = "*" пишем пользователю, что учетка не активирована.

пятница, 13 декабря 2019 г.

Пропадают классы css в письмах

#php #css #вёрстка #email


Есть верстка письма для рассылки. Все css-стили написаны в теле документа для рассылки.
Все стили привязаны к html-тегам с помощью классов.

Отправляем письмо с помощью mail(), PHP. Видим на почте (mail.ru, gmail.com, yandex.ru)
письмо без стилей. Причем нету даже css классов, есть только теги.

А если открыть тоже письмо в Thunderbird к примеру - то все классы есть и письмо
выглядит красиво.

Пробовал перемещать стили, ужимать стили, менять кавычки классов с двойных на одинарные,
читать текст рассылки из файла и вставлять его прямо в php-код.

Подскажите пожалуйста в чем проблема. Спасибо.
    


Ответы

Ответ 1



При верстке писем рекомендуется писать все стили инлайновыми. То есть не создавать селекторы, классы и так далее, а писать стили в теге style Например:


Ответ 2



Habrahabr Верстка email рассылок от А до Я для чайников Верстка почтовых рассылок: взгляд изнутри 10 рекомендаций по html-верстке электронных писем Верстка почтовых рассылок 5 правил верстки email-писем от Печкина How-to: Правила вёрстки email-писем

Ответ 3



В письмах можно использовать только инлайнстили. Всё остальное (стили, скрипты, классы) вырезают web-почтовики. Простая безопасность. Думаю что и в Thunderbird в настройках можно поставить такое поведение. Так что только инлайнстили. Если используются картинки в письме - то только через прямые ссылки и тег img, никаких background-image

среда, 11 декабря 2019 г.

Email рассылки — построение расписания

#алгоритм #email


Есть задача, которую необходимо решить, но нет особых познаний в области алгоритмов.
Поэтому прошу всех, кто «увидит» решение, или понимает в какую сторону смотреть (что
почитать/изучить), задать мне вектор для мысли.

Описание задачи.

Необходимо ежедневно формировать стек «Предложение — Сегмент» для совершения рассылки.

Сущности

Сегменты адресов (С = {1, 2, ..., n})
Вся база адресов делится на множество сегментов, каждый сегмент состоит из определенного
количества адресов. Допустим: всего в базе 9 млн. адресов, они разделены на 9к сегментов
по 1000 адресов каждый.

Предложения (П = {1, 2, ..., n})
Каждое отправленное письмо содержит в себе какое-то предложение (услуга/товар). По
сути, предложение — это шаблон письма. Допустим мы имеем в данный момент 9 предложений.

Ограничения


Отправка одного предложения может осуществляться с интервалом «не чаще, чем 1 раз
в 3 дня».
Поясню: если сегодня мы совершили рассылку предложения 1 (П1) сегментам с 1го по
100й, то в следующий раз мы можем совершить рассылку по П1 только через 3 дня, не ранее.
По идее каждый день можно рассылать любое количество предложений, но если предложений
9, тогда получается не более 3 предложений.
Отправка одного предложения одному сегменту может осуществляться «не чаще, чем 1
раз в 3 месяца».
Если взять за основу пояснение из предыдущего ограничения, получаем — сегментам с
1 по 100 предложение 1 мы сможем повторно отправить не раньше, чем через 90 дней.
Ежедневный лимит по отправленным письмам — 300 000.
Исходя из того, что в сегменте 1000 адресов, следует, что ежедневно мы можем задействовать
300 сегментов. Следует отметить, что уложится в 300к отправок (±) очень важно, т.е.
превышение или недобор необходимо свести к минимуму.
Каждый день одному сегменту можно отправить только одно предложение.
Т.е. нельзя сегменту 1 отправить несколько разных предложений в один день.


Дополнительные условия/требования


На основе статистики рассылки каждому сегменту и предложению устанавливается определенный
вес (коэффициент эффективности). Стек рассылки на сегодня должен формироваться с учетом
них, т.е. максимально эффективные пары «Сегмент-Предложение» приоритетнее.
Количество предложений и сегментов может меняться (например: получатель отписался
от рассылки; появились новые предложения). Новым сегментам/предложениям дается некая
«фора», т.е. чтобы определить эффективность, их необходимо «обстрелять», поэтому они
должны фигурировать в стеке на ближайшие 3 дня.


Таким образом мы должны каждый день получить стек, подобный этим:

День 1.


С101 … С200: П1
С201 … С300: П2
С301 … С400: П3


День 2.


С401 … С550: П4
С551 … С700: П5


День 3.
…

Это для примера, не стоит от этого отталкиваться.

Помимо формирования самого стека, необходимо также понимать — что будет происходить
при изменении количества предложений/сегментов. Не получится ли так, что рано или поздно
появятся дыры в расписании, т.е. дни, когда стек формировать будет не из чего.

Начал смотреть в сторону теории расписаний, но, есть подозрения, что могу ошибиться. 
    


Ответы

Ответ 1



Я бы использовал Рулетку. https://en.wikipedia.org/wiki/Fitness_proportionate_selection В основном этот алгоритм применяется для генетики, чтобы вывести генотипы следующего поколения на основе наиболее успешных фенотипов, но может применятся и для рассылки email, если опустить все, что нам не интересно из генетики (скрещивание, например). Идея такая - у каждого генотипа (сегмент, предложение) есть функция успешности - Fitness (подходящесть). Формируем все возможные генотипы (сегмент1, предложение1), (сегмент1, предложениеM), (сегментN,предложениеM) Всего таких будет M*N (300*9). Дальше, для каждого генотипа выводится фенотип по правилам. Например, есть примерно следующие правила, по порядку: Аддитивные: Всем +1 Новый +10 Эффективный +10 (или +какой-то вес). Не отправлялось данному сегменту без учета предложения X дней: +(X*F) F - экспериментальный коэффициент. Прибавляем баллов тем, кому давно ничего не отправлялось. Мультипликативные (множим на 0): Отправлялось в последние три дня: * 0 Данное предложение данному сегменту отправлялось менее месяца назад: * 0 Например, получаем такие значения: (1,1) -> 11 (1,2) -> 1 (2,1) -> 21 (2,2) -> 0 Те, кто набрал в итоге 0 отбраковываем. Теперь рисуем рулетку. Рулетка размечается так: Fitness каждого фенотипа это кол-во фишек, которые "игрок" выложил. Фишки раскладываются так, чтобы занять весь круг. На самом деле, мы можем задать размер круга так, чтобы заведомо точно вместить все фишки. Если "фишкки" не целочисленные, то считаем что это длина сегмента окружности в пропорции. Суммируем Fitness всех фенотипов, и получаем (11 + 1 + 21) = 33 - это длина окружности. 1) Кидаем шарик: i = random(1,33) Например, i = 13 *****************|<- шарик выпал сюда, берем (2,1) 0|*****11****|1|**********21*********|33 Значит, набираем в рассылку (2,1), если ее у же там нет. Если мы набрали достаточную рассылку (размер успешной популяции, в терминах генетики), то отсылаем, и ждем день, иначе переходим на 1) У этого алгоритма есть проблема - он не масштабируется от размера популяции, тоесть для вычисления куда попал шарик нужно суммировать в среднем N*M/2 элементов (наш размер популяции). Это все сворачивается в более эффективный алгоритм, если мы будем не просто шарик кидать, а продолжать "катить" его: (1,1) -> 11 11 (1,2) -> 1 12 (2,1) -> 21 33 (круг) (1,1) -> 11 44 (1,2) -> 1 45 (2,1) -> 21 66 И шарик двигаем каждый раз на случайное число от 1 до K например. K - достоточно большое, например - максимальный балл, иначе можем набрать некачественную популяцию. В этом случае алгоритм будет за линейное время работать. Можно было бы вместо случайных чисел использовать просто сортировку по баллам, и брать первые 300k, но это грозит тем, что решение будет осциллировать. Этот алгоритм эффективно будет работать пока число генотипов существенно больше числа разрешенных рассылок в день, хотя бы вдвое, и если это будет не так, нужно будет как-то учесть. Иначе шарик на конечном этапе будет кататься "по пустому кругу". Как вариант - если такая ситуация возникает, то круг переделывается из остатков, и алгоритм запускается снова. Чем хорошо такое решение - можно независимо от алгоритма регулировать правила, веса, коэффициенты и запреты (умножение на ноль).