Страницы

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

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

пятница, 13 марта 2020 г.

Самописный СМТП-сервер

#c_sharp #многопоточность #smtp


Я написал СМТП сервер, но работает он некорректно вот в каком моменте: 
если я 1 раз подключусь к нему через телнет, он ответит нормально (рис 1-2.), но
если я еще раз подключусь через другую консоль cmd, то я появится только черный экран
и все(рис3):


(рис 1)


(рис 2)


(рис 3)

В последнем случае что-бы я ни вводил, на экране ничего не отобразится, и даже не
залогируется моим СМТП

В первом же случае, мои команды отображаются в консоли, они логируюстя сервером и
я вижу в этой консоли ответ (рис 4):


(рис 4)

Т.е., что я вижу, один клиент к нему подключается, работает нормально сервер, во
всех остальных случаях он работает не корректно (верно?)

Вот как я реализовал СМТП-сервер (это win-сервис):

 protected override void OnStart(string[] args)
        {
SmtpHelper s = new SmtpHelper(this);
System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(StartListen),
(object)s );
}

 void StartListen(object s)
        {
            try
            {
                var a = (SmtpHelper)s;
                a.Listen(); //запуск 
            }
            catch (Exception ex)
            {
                l.Write("Error (StartListen(object s)): " + ex.ToString());
                throw;
            }

        }




public void Listen()
        {
            try
            {
                SMTP_Listener = new TcpListener(IPAddress.Any, port); 
                SMTP_Listener.Start();

                while (true)
                {
                    clientSocket = SMTP_Listener.AcceptSocket();

                    _sessionId = clientSocket.GetHashCode().ToString();

                    _email.sessionId = Convert.ToInt32(_sessionId);


                    StartProcessing(newController);
                    l.Write("we are there");

                   // System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(ClientThread),
SMTP_Listener.AcceptTcpClient());
                }

            }
            catch (Exception ex)
            {
                l.Write("SMTP Listen Error: " + ex.ToString());
                throw;
            }
        }



void StartProcessing(ClientSessionController newController)
        {

            try
            {
                m_ConnectedIp = ParseIP_from_EndPoint(clientSocket.RemoteEndPoint.ToString());
                m_ConnectedHostName = GetHostName(m_ConnectedIp);

                _email.ip = m_ConnectedIp;
                _email.port = 25;


                SendData("220 " + System.Net.Dns.GetHostName() + " Service ready\r\n");

                //if (!clientSocket.Connected)
                //    clientSocket.Connect(IPAddress.Any, port);

                //РАБОТА С ВХОДНЫМИ ДАННЫМИ
                while (true)
                {
                    //если есть данные, то считаем их
                    if (clientSocket.Available > 0)
                    {
                        //получение команды от клиента
                        string lastCmd = ReadLine();

                        //парсим команду от клиента (HELO, RCPT, DATA etc.)
                        if (lastCmd.Trim() != String.Empty)
                            ProceedCommand(lastCmd, newController);
                        //break;
                    }
                    else
                    {
                      //dump:  l.Write("[Socket isn't available now]");
                    }
                }               
            }
            catch (Exception ex)
            {
                throw;
            }

        }


ВОПРОС: 

Подскажите пожалуйста, как мне сделать так, чтобы мой сервис мог одинаково обслужить
всех подключаемых клиентов, а не только первого?
    


Ответы

Ответ 1



В подобных случаях обычно делают один поток слушатель, который прослушивает нужный порт. Когда подключается клиент создаётся новый поток для обслуживания непосредственно его и слушатель передаёт работу с клиентом этому потоку. При завершении клиентом работы с сервером этот поток уничтожается. Приблизительно как-то так.

суббота, 7 марта 2020 г.

Не отправляется письмо через smtp mail - время ожидания операции истекло

#c_sharp #net #веб_программирование #smtp


Написал маленькую прогу на WinForms с опцией отправки сообщения. Собсно код :

   SmtpClient client = new SmtpClient("smtp.mail.ru", 465);
            client.Credentials = new NetworkCredential("vasiliy.aksenov.97@mail.ru",
"11aa11aa");
            client.EnableSsl = true;  
            MailMessage mail = new MailMessage();
            mail.From = new MailAddress("vasiliy.aksenov.97@mail.ru");
            mail.To.Add("vasiliy.aksenov.97@mail.ru");
            mail.Subject = "Получен новый заказ на " + OrderData.clothingTypeRuss;
            mail.Body = "test";
        try
        {
            client.Send(mail);
            MessageBox.Show("Заказ успешно отправлен ", "Отправка");
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, ex.Source);
        }


не отправляет, пишет что время ожидания превышено. и тоже самое с smtp от gmail.
Может что то в коде не правильно? Хотя по отладке видно что тормозит именно на 
   client.Send(mail); Подскажите как решить проблему?
    


Ответы

Ответ 1



Отлично, вы верно решили проблему. Сейчас давайте определимся с причинами такого поведения. Существует два способа соединения по протоколу SMTP c использованием SSL: Explicit SSL Implicit SSL Explicit SSL использует порты 25 (или 587), или же, возможно, порт 2525 (не стандартный) Explicit SSL означает, что клиент сначала подключается по незащищенному каналу, посылает команду EHLO, и если сервер сообщает о том, что шифрование поддерживается, то для включения шифрования клиент посылает команду STARTTLS, затем все дальнейшие коммуникации (включая аутентификацию) между клиентом и сервером уже защищены. Implicit SSL использует порт 465 и отличается тем, что соединение сразу устанавливается по TLS/SSL. В настоящее время класс SmtpClient поддерживает только Explicit SSL, потому что Implicit SSL до сих пор не стандартизирован.

Ответ 2



Вот Вам отличный вариант отправки сообщения на почту: Стандартные, используемые порты Некоторые интернет-провайдеры в целях предотвращения рассылки СПАМ закрывают для доступа 25-й порт, который требуется для работы SMTP-протокола. Если закрыт 25-й порт. Если почта у вас не отправляется, вероятно ваш Интернет-провайдер заблокировал 25-й порт, используемый для работы протокола SMTP. Это ограничение можно обойти, используя порт 587 (без шифрования или с использованием TLS-шифрования) или 465 (с использованием SSL-шифрования) обычно не блокируется. using System.Net; using System.Net.Mail; using System.Text; using System.Windows.Forms; public class SettingMessage { public static void MessageSend() // можете добавить аргументы { MailMessage message = new MailMessage(); SmtpClient client = new SmtpClient("smtp.mail.ru", Convert.ToInt32(0x19)) // сервер,порт { Credentials = new NetworkCredential("Ваш Email", "Ваш пароль"), EnableSsl = true // обязательно! }; message.From = new MailAddress("От кого посылать"); message.To.Add(new MailAddress("Кому посылать")); message.Subject = "Заголовок"; message.SubjectEncoding = Encoding.UTF8; message.Body = "Текст в форме сообщения"; message.BodyEncoding = Encoding.UTF8; // кодировка string fileName = @"C:\Resume.txt"; // какой-нибудь файл Attachment item = new Attachment(fileName); message.Attachments.Add(item);// добавляем файл к сообщению client.Send(message); // отправка сообщения MessageBox.Show("Сообщение отправлено успешно)))"); } }

Ответ 3



Проблема была в порте. SmtpClient client = new SmtpClient("smtp.mail.ru", 2525); так работает

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

smtplib в Python c smtp.yandex.ru

#python #python_3x #smtp


Юзаю Python 3.4.3. Хочу написать простенький скрипт, который будет отсылать на заданный
ящик текстовую информацию. Нашёл : следующий пример. В режиме интерпретатора ввожу:

>>> import smtplib
>>> server = smtplib.SMTP('smtp.yandex.ru', 465)


И на второй строчке интерпретатор наглухо виснет. Для Яндекса инфу о сервере брал отсюда.

UPD: если использовать то же для Gmail:

server = smtplib.SMTP('smtp.gmail.com', 587)


То всё норм. Однако хочется (т.е. имеется ящик) подключаться к Яндексу. Возможно это?

UPD2: если для Яндекса юзать порт 587, то вторая строчка тоже проходит. Однако третья:

server.login("youremailusername", "password")


Приводит к поднятию эксепшена smtplib.SMTPServerDisconnected

UDP3: нашёл этот вопрос. Делаю так:

import smtplib
smtp = smtplib.SMTP_SSL()
smtp.connect('smtp.yandex.ru')


И вываливается ssl.SSLEOFError

UPD4: Нашёл эту ссылку и сделал так:

server = smtplib.SMTP_SSL('smtp.yandex.ru:465')
server.login('login', 'pass')


И всё заработало. Заработало в том смысле, что пришло smtplib.SMTPAuthenticationError
с сообщением, суть которого заключается в том что я веду себя как робот и мне надо
привязать номер мобильного чтобы система перестала видеть во мне робота. Видимо, защита
от подбора пароля.
    


Ответы

Ответ 1



@Xyanight (надеюсь я его позвал): для Gmail import smtplib def sendEMail(text): server = smtplib.SMTP("smtp.gmail.com", 587) server.ehlo() server.starttls() server.login("login", "pass") message = "\r\n".join([ "From: от кого", "To: кому", "Subject: тема", "", str(text) ]) server.sendmail("от кого", "кому", message) server.quit()

Ответ 2



Для яндекса у меня получилось пройти аутентификацию AUTH PLAIN через SSL соединение. Работает такой код: #!/usr/bin/env python3 import smtplib as smtp from getpass import getpass email = input('введите почту: \n') password = getpass('введите пароль: ') dest_email = input('введите адрес получателя: \n') subject = input('тема письма: \n') email_text = input('текст письма: \n' ) message = 'From: {}\nTo: {}\nSubject: {}\n\n{}'.format(email, dest_email, subject, email_text) server = smtp.SMTP_SSL('smtp.yandex.com') server.set_debuglevel(1) server.ehlo(email) server.login(email, password) server.auth_plain() server.sendmail(email, dest_email, message) server.quit()

Ответ 3



У меня вот так заработало для Яндекса: import smtplib email = 'some@mail.ru' password = 'some_pass' server = smtplib.SMTP('smtp.yandex.ru', 587) server.ehlo() # Кстати, зачем это? server.starttls() server.login(email, password) dest_email = 'another@mail.ru' subject = 'Booking from chatbot' email_text = 'Text' message = 'From: %s\nTo: %s\nSubject: %s\n\n%s' % (email, dest_email, subject, email_text) server.set_debuglevel(1) # Необязательно; так будут отображаться данные с сервера в консоли server.sendmail(email, dest_email, message) server.quit()

воскресенье, 12 января 2020 г.

django. отправка email на localhost`e

#python #django #smtp


Подскажите, каким образом я могу отправить письмо на почтовый ящик на локальном сервере.
джанго работает на localhost:8080
для отправки (как прочитал в документации) нужен SMTP сервер. Запускаю тоже локальный

python -m smtpd -n -c DebuggingServer localhost:1025


получаю localhost:1025
во вьюхе

send_mail('theme', 'my messege', 'admins@studio.ru',
['a@a.ru'])


ловил разные ошибки, например с getaddrinfo(host, port)
добавил во вьюху

import socket
socket.getaddrinfo('localhost', 8080)


сейчас ошибка [Errno 11004] getaddrinfo failed 

(code, msg) = self.connect(host, port)


я вообще не знаю как настраивать (новичек) и написал в сеттингс:

EMAIL_HOST = 'localhost:8080'
EMAIL_HOST_USER = 'username@domain.ru'
EMAIL_HOST_PASSWORD = ''
EMAIL_PORT = 1025


у верен в сеттингс проблема. Подскажите как все правильно настроить? 
    


Ответы

Ответ 1



Для разработки мне подходит решение в одну строчку. Все отправленные письма будут просто выводится в консоль(stdout). EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' Если вам все же необходимо настроить работу почты через отправку сервером. Запускаем питоновский почтовик python -m smtpd -n -c DebuggingServer localhost:1025 В файл настроек приложения EMAIL_HOST = 'localhost' EMAIL_PORT = 1025 Всё :) Подробнее: Ссылка на документацию Stackoverflow Test sending email without email server

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

Настройка smtp Yandex в Rails

#ruby_on_rails #яндекс #smtp


Добрый день

Для реализации отправки сообщений из приложения было опробовано два пути: первый
- компактный, и хоть не без проблем, но отправка сообщения происходит.

Второй (следуя руководству по ActionMailer) - не такой компактный и сообщения не
отправляются.

Хочу разобраться с обоими

Вариант 1

#app/controllers/feedback_info_controller.rb

def send_mail
 smtp = Net::SMTP.new( "smtp.yandex.ru", 587 )
 smtp.enable_starttls
 smtp.start( "yandex.ru", "my_adr@yandex.ru", "пароль", :plain ) do |conn|
 conn.send_message "Сообщение", "my_adr@yandex.ru", "получатель@rambler.ru"
end


В этом случае, на почту получатель@rambler.ru приходит письмо (без темы) от MAILER-DAEMON@
со следующим содержанием:


  by mail172.rambler.ru (rmaild SMTP 1.2.41)
  
  with ESMTP id 292593804 for получатель@rambler.ru; Mon, 24 Aug 2015 11:13:46 +0300
  
  Received: from forward22m.cmail.yandex.net (forward22m.cmail.yandex.net [5.255.216.16])

    by mx2.mail.rambler.ru (Postfix) with ESMTP id 65FF15CA8
    for <получатель@rambler.ru>; Mon, 24 Aug 2015 11:13:46 +0300 (MSK) 

  
  Received: from smtp3m.mail.yandex.net (smtp3m.mail.yandex.net [IPv6:2a02:6b8:0:2519::125])

    by forward22m.cmail.yandex.net (Yandex) with ESMTP id 488F18046B
    for <получатель@rambler.ru>; Mon, 24 Aug 2015 11:13:46 +0300 (MSK)

  
  Received: from smtp3m.mail.yandex.net (localhost [127.0.0.1])

    by smtp3m.mail.yandex.net (Yandex) with ESMTP id 2C1A127A05B8
    for <получатель@rambler.ru>; Mon, 24 Aug 2015 11:13:46 +0300 (MSK)

  
  Received: by smtp3m.mail.yandex.net (nwsmtp/Yandex) with ESMTPSA id lnLUHk87ag-DjpWkB95;
  
  Mon, 24 Aug 2015 11:13:45 +0300
  
  (using TLSv1 with cipher AES128-SHA (128/128 bits))
  
  (Client certificate not present)
  
  Message-Id: <20150824111345.DjpWkB95@smtp3m.mail.yandex.net>
  
  Date: Mon, 24 Aug
  
  2015 11:13:45 +0300 
  
  From: MAILER-DAEMON 
  
  To: undisclosed-recipients:;
  
  X-Spam: yes


Вариант 2

Создание и использование рассыльщика FeedbackMailer

   #app/mailers/application_mailer.rb
    class ApplicationMailer < ActionMailer::Base 
    end

   #app/mailers/feedback_mailer.rb
    class FeedbackMailer < ApplicationMailer
    def feedback_email
      mail(from: 'my_adr@yandex.ru', to: 'получатель@rambler.ru', subject: 'тема')
    end
    end 

   #app/controllers/feedback_info_controller.rb
    def feedback_send
       FeedbackMailer.feedback_email
    end

  #config/environments/development.rb
    config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
    config.action_mailer.delivery_method = :smtp
    config.action_mailer.smtp_settings = {
        address: 'smtp.yandex.ru',
        port: 587,
        domain: 'yandex.ru',
        authentication: 'plain',
        user_name: 'my_adr@yandex.ru',
        password: 'пароль',
        enable_starttls_auto: true
    }


с такими настройками ничего не происходит
    


Ответы

Ответ 1



config.action_mailer.smtp_settings = { tls: true, ... Без этого yandex не работает. Причем tls: в официальной документации нет.

Ответ 2



Работает с такими настройками: #development.rb config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { :tls => true, address: 'smtp.yandex.ru', port: 465, domain: 'yandex.ru', authentication: 'plain', user_name: 'name@yandex.ru', password: 'пароль' } #mailers/application_mailer.rb class ApplicationMailer < ActionMailer::Base end #mailers/feedback_mailer.rb class FeedbackMailer < ApplicationMailer def feedback_email (name, phone, comment) @name = name @phone = phone @comment = comment mail(from: 'name@yandex.ru', to: 'adrr@example.com', subject: 'Тема письма') end end #controllers/feedback_info_controller.rb def feedback_send @name = CGI.escapeHTML(params[:feedback_info][:name]) @phone = CGI.escapeHTML(params[:feedback_info][:phone]) @comment = CGI.escapeHTML(params[:feedback_info][:comment]) FeedbackMailer.feedback_email(@name,@phone,@comment).deliver_now end

Ответ 3



Во втором варианте вы пропустили, собственно, доставку. Вы создали объект письма, но не запустили отправку. С Rails 4.2+ можно спокойно использовать .deliver_later: FeedbackMailer.feedback_email.deliver_later Но сначала перечитайте руководство, особенно этот абзац: Поведением Active Job по умолчанию является запуск заданий :inline. Поэтому можно использовать deliver_later для отсылки писем прямо сейчас, а если позже решите отправлять письма в фоновой задаче, вам нужно будет всего лишь настроить Active Job для использования бэкэнда очередей (Sidekiq, Resque и т.п.).

Ответ 4



В Rails 5 для настройки в config/environments/production.rb добавил: config.action_mailer.default_url_options = { host: 'www.yoursite.ru' } config.action_mailer.perform_deliveries = true config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { tls: true, address: "smtp.yandex.com", port: 465, domain: "yandex.com", authentication: "plain", enable_starttls_auto: true, user_name: 'youremail@yandex.ru', password: 'yourpassword' } Все отлично работает, в том числе с почтой для домена (pdd.yandex.ru). Однако в отличии от gmail, письмо не сохраняется в папке отправленные на сервере.

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

Отправка почты c#

#c_sharp #smtp


EmailSend.SendMailRu(item.Email, tema, body, item.FromEmail, item.SmtpClient, item.SmtpPort,
item.LoginEmail, item.PasswordEmail, file);


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

public static void SendMailRu(string toEmail, string subject, string body, string
from, string smtp_client, int smtp_port, string login, string password,string file)
{
    SmtpClient client = new SmtpClient(smtp_client, smtp_port);

    client.Credentials = new NetworkCredential(login, password);
    MailMessage message = new MailMessage();

    message.To.Add(toEmail);
    message.BodyEncoding = System.Text.Encoding.UTF8;
    message.SubjectEncoding = System.Text.Encoding.GetEncoding("windows-1251");
    message.IsBodyHtml = true;
    message.From = new MailAddress(from);

    message.Subject = subject;
    message.Body = HEADER+body+ FOOTER;

    if (smtp_port!=25)
    {
        client.EnableSsl = true;
    }

    if (!String.IsNullOrEmpty(file))
    {
        Attachment sendFile = new Attachment(file);
        message.Attachments.Add(sendFile);
    }

    client.Send(message);
}

    


Ответы

Ответ 1



настройте в DNS подпись DKIM, должно заработать. Только подождать придеться, пока DNS обновятся немного о DKIM тут http://habrahabr.ru/post/106589/

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

Где и как хранить пароль для SmtpClient?

#c_sharp #smtp #пароль


Планирую из программы отправлять Email по определенным событиям.
Все настройки храню через App.config

Как быть с паролем? Хранить тут же, зашифровав?
Если шифровать с ключом, то ключ где хранить?
    


Ответы

Ответ 1



Я не знаю простых способов порешать эту проблему. До тех пор, пока мы работаем в энтерпрайз-приложениях (читай: есть application сервер) мы всегда может договариваться о том, чтобы хранить пароль в app.config ("всё равно доступ на сервер открыт только тем, кому надо") чуть ли не в явном виде. Ещё лучше, когда есть домен и мы можем использовать возможность не указывать пароль вообще. Т.е. для SQL соединений мы можем указать Integrated Security=True в connection string, для почты мы можем обращаться к корпоративному Exchange Server'у, который знает, что служба запущена от такой-то доменной учётки. Как только мы уходим в создание приложений, рассчитанных на b2c сегмент, т.е. продаём домашнему пользователю ПО, то вся схема начинает рассыпаться как карточный домик. И вместо почтовика приходится коннектиться к какому-то бесплатному gmail/rambler/mailru/yandex и т.п. сервису, и SQL уже полноценно не подымешь... Я не знаю, возможно ли вообще общее решение, когда у вас всё для расшифровки находится в одном месте. Вон, даже настройки ODBC винда до сих пор хранит в явном виде в реестре. :( Единственное что мне приходит в голову: шифровать данные пользователя паролем пользователя (он же нигде не хранится), однако это решение с побочками (забыл пароль - потерял настройки, нельзя зашить пароль в дистрибутив) Какие-то костыли встречал (например), но с такой кучей побочек (только веб-конфиг, только коннекшн стринг и т.п.), что пользоваться неудобно. На дворе шёл уже 2019 год... :(

вторник, 10 декабря 2019 г.

Многопоточный прием данных

#c_sharp #многопоточность #smtp


Есть СМТП-сервис. Он слушает 25ый порт:

SMTP_Listener = new TcpListener(IPAddress.Any, 25); 
SMTP_Listener.Start();


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


  
  Клиент1: команда "HELLO 11111" 
  Клиент2: команда "HELLO 22222"
  Клиент3: команда "HELLO 33333"
  


Я получаю "HELLO 11" от первого клиента, от второго- "LO 22", для третьего - "LO
3333" (например).

Подскажите, как правильно разделить чтение от нескольких клиентов?

У меня каждый клиент работает в отдельном потоке.

КОД приема сообщений от клиентов:

/// 
/// Считываем команду клиента
/// 
/// 
private string ReadLine() {
    try {
        long lastDataTime = DateTime.Now.Ticks;
        ArrayList lineBuf = new ArrayList();
        byte prevByte = 0;

        while (true) {
            if (clientSocket == null) l.Write(" !!! clientSocket is NULL");

            if (!clientSocket.Connected) l.Write(" !!! сокет не включен!");

            if (clientSocket.Available > 0) {
                // Read next byte
                byte[] currByte = new byte[1];
                int countRecieved = clientSocket.Receive(currByte, 1, SocketFlags.None);

                // Count must be equal. Eg. some computers won't give byte at first
read attempt
                if (countRecieved == 1) {
                    lineBuf.Add(currByte[0]);

                    // Line found
                    if ((prevByte == (byte)
                    '\r' && currByte[0] == (byte)
                    '\n')) {
                        byte[] retVal = new byte[lineBuf.Count - 2]; // Remove  
                        lineBuf.CopyTo(0, retVal, 0, lineBuf.Count - 2);

                        return System.Text.Encoding.Default.GetString(retVal).Trim();
                    }

                    // Store byte
                    prevByte = currByte[0];
                    //l.Write("prevByte = " + prevByte);
                    //// Check if maximum length is exceeded
                    //if (lineBuf.Count > maxLen)
                    //{
                    //    throw new Exception( "Maximum line length exceeded");
                    //}

                    // reset last data time
                    lastDataTime = DateTime.Now.Ticks;
                    //l.Write("lastDataTime = " + lastDataTime);
                }
            } else {
                // l.Write("clientSocket.Available: " + clientSocket.Available.ToString());
// тут всегда 0
                //---- Time out stuff -----------------------//
                if (DateTime.Now.Ticks > lastDataTime + ((long)(60000)) * 10000) {
                    l.Write("ERROR: Read timeout: " + (((long)(60000)) * 10000).ToString());

                    //clientSocket.Close();
                    l.Write("Сокет закрыт из-за простоя в " + (((long)(60000)) *
10000).ToString() + " м-сек.");

                    // throw new Exception("Read timeout");
                    return ""; // ?????????????????????????????????????????????????????????????????????
                }
                System.Threading.Thread.Sleep(100);
                //------------------------------------------//
            }
        }

    } catch (Exception x) {
        l.Write("EROR ReadLine(): " + x.ToString());
        throw new Exception(x.Message);
    }
}



  UPD:


 public void Listen()
        {
            int iter = 0;

            try
            {
                l.Write("***************START*******************");
                l.Write("SMTP server started " + DateTime.Now.ToString());

                SMTP_Listener = new TcpListener(IPAddress.Any, port); 
                SMTP_Listener.Start();


                while (true)
                {

//тут я определяю что у нас есть клиент
                    clientSocket = SMTP_Listener.AcceptSocket();                

                    _sessionId = clientSocket.GetHashCode().ToString();

                    _email.sessionId = Convert.ToInt32(_sessionId);

                    l.Write("New session: " + _sessionId);

//и в отдельный поток его
                    Thread newClient = new Thread(StartProcessing);

                    l.Write("Создан поток для обработки клиента " + _sessionId);
                    UserSessionController.AddSession( Convert.ToInt32(_sessionId ) );

                    newClient.Name = _sessionId;
                    newClient.IsBackground = true; // ???
                    newClient.Start();          
                } 

            }
            catch (Exception ex)
            {
                l.Write("SMTP Listen Error: " + ex.ToString());
                throw;
            }
        }

    


Ответы

Ответ 1



private Socket clientSocket у вас один общий экземпляр сокета для всех клиентов. когда подключается новый клиент clientSocket = SMTP_Listener.AcceptSocket(); вы выбрасываете сокет, который был открыт при подключении предыдущего клиента. В результате все потоки у вас читают из this.clientSocket, ссылающегося на сокет, открытый для последнего подключенного клиента. Т.е. все, что прислали предыдущие клиенты, но что не успели вычитать - уходит вникуда. А все, что присылает последний клиент, рвут между собой все читающие потоки. Вам стоит перенести код, связанный с обработкой клиента, в отдельный класс, чтобы получить отдельный экземпляр на каждого клиента: class ClientProcessor() { private Socket clientSocket; public ClientProcessor(Socket clientSocket) { this.clientSocket = clientSocket; } string ReadLine() {....} void StartProcessing(); } и создавать новый экземпляр для каждого подключившегося клиента: var processor = new ClientProcessor(SMTP_Listener.AcceptSocket()); Thread newClient = new Thread(processor.StartProcessing);

воскресенье, 24 ноября 2019 г.

Как из скрипта на Питоне послать письмо с вложением?


Нужен простейший пример посылки письма с вложением через внешний SMTP сервер, например, smtp.yandex.ru.    


Ответы

Ответ 1



from smtplib import SMTP_SSL from email.MIMEMultipart import MIMEMultipart from email.MIMEBase import MIMEBase from email import Encoders import os filepath = "/path/to/file" basename = os.path.basename(filepath) address = "name@server" # Compose attachment part = MIMEBase('application', "octet-stream") part.set_payload(open(filepath,"rb").read() ) Encoders.encode_base64(part) part.add_header('Content-Disposition', 'attachment; filename="%s"' % basename) # Compose message msg = MIMEMultipart() msg['From'] = address msg['To'] = address msg.attach(part) # Send mail smtp = SMTP_SSL() smtp.connect('smtp.yandex.ru') smtp.login(address, 'password') smtp.sendmail(address, address, msg.as_string()) smtp.quit()

суббота, 22 июня 2019 г.

Самописный СМТП-сервер

Я написал СМТП сервер, но работает он некорректно вот в каком моменте: если я 1 раз подключусь к нему через телнет, он ответит нормально (рис 1-2.), но если я еще раз подключусь через другую консоль cmd, то я появится только черный экран и все(рис3):
(рис 1)
(рис 2)
(рис 3)
В последнем случае что-бы я ни вводил, на экране ничего не отобразится, и даже не залогируется моим СМТП
В первом же случае, мои команды отображаются в консоли, они логируюстя сервером и я вижу в этой консоли ответ (рис 4):
(рис 4)
Т.е., что я вижу, один клиент к нему подключается, работает нормально сервер, во всех остальных случаях он работает не корректно (верно?)
Вот как я реализовал СМТП-сервер (это win-сервис):
protected override void OnStart(string[] args) { SmtpHelper s = new SmtpHelper(this); System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(StartListen), (object)s ); }
void StartListen(object s) { try { var a = (SmtpHelper)s; a.Listen(); //запуск } catch (Exception ex) { l.Write("Error (StartListen(object s)): " + ex.ToString()); throw; }
}

public void Listen() { try { SMTP_Listener = new TcpListener(IPAddress.Any, port); SMTP_Listener.Start();
while (true) { clientSocket = SMTP_Listener.AcceptSocket();
_sessionId = clientSocket.GetHashCode().ToString();
_email.sessionId = Convert.ToInt32(_sessionId);
StartProcessing(newController); l.Write("we are there");
// System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(ClientThread), SMTP_Listener.AcceptTcpClient()); }
} catch (Exception ex) { l.Write("SMTP Listen Error: " + ex.ToString()); throw; } }

void StartProcessing(ClientSessionController newController) {
try { m_ConnectedIp = ParseIP_from_EndPoint(clientSocket.RemoteEndPoint.ToString()); m_ConnectedHostName = GetHostName(m_ConnectedIp);
_email.ip = m_ConnectedIp; _email.port = 25;
SendData("220 " + System.Net.Dns.GetHostName() + " Service ready
");
//if (!clientSocket.Connected) // clientSocket.Connect(IPAddress.Any, port);
//РАБОТА С ВХОДНЫМИ ДАННЫМИ while (true) { //если есть данные, то считаем их if (clientSocket.Available > 0) { //получение команды от клиента string lastCmd = ReadLine();
//парсим команду от клиента (HELO, RCPT, DATA etc.) if (lastCmd.Trim() != String.Empty) ProceedCommand(lastCmd, newController); //break; } else { //dump: l.Write("[Socket isn't available now]"); } } } catch (Exception ex) { throw; }
}
ВОПРОС:
Подскажите пожалуйста, как мне сделать так, чтобы мой сервис мог одинаково обслужить всех подключаемых клиентов, а не только первого?


Ответ

В подобных случаях обычно делают один поток слушатель, который прослушивает нужный порт. Когда подключается клиент создаётся новый поток для обслуживания непосредственно его и слушатель передаёт работу с клиентом этому потоку. При завершении клиентом работы с сервером этот поток уничтожается.
Приблизительно как-то так.

среда, 22 мая 2019 г.

Не отправляется письмо через smtp mail - время ожидания операции истекло

Написал маленькую прогу на WinForms с опцией отправки сообщения. Собсно код :
SmtpClient client = new SmtpClient("smtp.mail.ru", 465); client.Credentials = new NetworkCredential("vasiliy.aksenov.97@mail.ru", "11aa11aa"); client.EnableSsl = true; MailMessage mail = new MailMessage(); mail.From = new MailAddress("vasiliy.aksenov.97@mail.ru"); mail.To.Add("vasiliy.aksenov.97@mail.ru"); mail.Subject = "Получен новый заказ на " + OrderData.clothingTypeRuss; mail.Body = "test"; try { client.Send(mail); MessageBox.Show("Заказ успешно отправлен ", "Отправка"); } catch (Exception ex) { MessageBox.Show(ex.Message, ex.Source); }
не отправляет, пишет что время ожидания превышено. и тоже самое с smtp от gmail. Может что то в коде не правильно? Хотя по отладке видно что тормозит именно на client.Send(mail); Подскажите как решить проблему?


Ответ

Отлично, вы верно решили проблему. Сейчас давайте определимся с причинами такого поведения.
Существует два способа соединения по протоколу SMTP c использованием SSL:
Explicit SSL Implicit SSL
Explicit SSL использует порты 25 (или 587), или же, возможно, порт 2525 (не стандартный)
Explicit SSL означает, что клиент сначала подключается по незащищенному каналу, посылает команду EHLO, и если сервер сообщает о том, что шифрование поддерживается, то для включения шифрования клиент посылает команду STARTTLS, затем все дальнейшие коммуникации (включая аутентификацию) между клиентом и сервером уже защищены.
Implicit SSL использует порт 465 и отличается тем, что соединение сразу устанавливается по TLS/SSL.
В настоящее время класс SmtpClient поддерживает только Explicit SSL, потому что Implicit SSL до сих пор не стандартизирован.

пятница, 15 марта 2019 г.

smtplib в Python c smtp.yandex.ru

Юзаю Python 3.4.3. Хочу написать простенький скрипт, который будет отсылать на заданный ящик текстовую информацию. Нашёл : следующий пример. В режиме интерпретатора ввожу:
>>> import smtplib >>> server = smtplib.SMTP('smtp.yandex.ru', 465)
И на второй строчке интерпретатор наглухо виснет. Для Яндекса инфу о сервере брал отсюда
UPD: если использовать то же для Gmail:
server = smtplib.SMTP('smtp.gmail.com', 587)
То всё норм. Однако хочется (т.е. имеется ящик) подключаться к Яндексу. Возможно это?
UPD2: если для Яндекса юзать порт 587, то вторая строчка тоже проходит. Однако третья:
server.login("youremailusername", "password")
Приводит к поднятию эксепшена smtplib.SMTPServerDisconnected
UDP3: нашёл этот вопрос. Делаю так:
import smtplib smtp = smtplib.SMTP_SSL() smtp.connect('smtp.yandex.ru')
И вываливается ssl.SSLEOFError
UPD4: Нашёл эту ссылку и сделал так:
server = smtplib.SMTP_SSL('smtp.yandex.ru:465') server.login('login', 'pass')
И всё заработало. Заработало в том смысле, что пришло smtplib.SMTPAuthenticationError с сообщением, суть которого заключается в том что я веду себя как робот и мне надо привязать номер мобильного чтобы система перестала видеть во мне робота. Видимо, защита от подбора пароля.


Ответ

@Xyanight (надеюсь я его позвал): для Gmail
import smtplib
def sendEMail(text): server = smtplib.SMTP("smtp.gmail.com", 587) server.ehlo() server.starttls() server.login("login", "pass") message = "
".join([ "From: от кого", "To: кому", "Subject: тема", "", str(text) ]) server.sendmail("от кого", "кому", message) server.quit()

четверг, 7 марта 2019 г.

django. отправка email на localhost`e

Подскажите, каким образом я могу отправить письмо на почтовый ящик на локальном сервере. джанго работает на localhost:8080 для отправки (как прочитал в документации) нужен SMTP сервер. Запускаю тоже локальный
python -m smtpd -n -c DebuggingServer localhost:1025
получаю localhost:1025 во вьюхе
send_mail('theme', 'my messege', 'admins@studio.ru', ['a@a.ru'])
ловил разные ошибки, например с getaddrinfo(host, port) добавил во вьюху
import socket socket.getaddrinfo('localhost', 8080)
сейчас ошибка [Errno 11004] getaddrinfo failed
(code, msg) = self.connect(host, port)
я вообще не знаю как настраивать (новичек) и написал в сеттингс:
EMAIL_HOST = 'localhost:8080' EMAIL_HOST_USER = 'username@domain.ru' EMAIL_HOST_PASSWORD = '' EMAIL_PORT = 1025
у верен в сеттингс проблема. Подскажите как все правильно настроить?


Ответ

Для разработки мне подходит решение в одну строчку. Все отправленные письма будут просто выводится в консоль(stdout).
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
Если вам все же необходимо настроить работу почты через отправку сервером. Запускаем питоновский почтовик
python -m smtpd -n -c DebuggingServer localhost:1025
В файл настроек приложения
EMAIL_HOST = 'localhost' EMAIL_PORT = 1025
Всё :)
Подробнее:
Ссылка на документацию Stackoverflow Test sending email without email server

четверг, 1 ноября 2018 г.

Настройка smtp Yandex в Rails

Добрый день
Для реализации отправки сообщений из приложения было опробовано два пути: первый - компактный, и хоть не без проблем, но отправка сообщения происходит.
Второй (следуя руководству по ActionMailer) - не такой компактный и сообщения не отправляются.
Хочу разобраться с обоими
Вариант 1
#app/controllers/feedback_info_controller.rb
def send_mail smtp = Net::SMTP.new( "smtp.yandex.ru", 587 ) smtp.enable_starttls smtp.start( "yandex.ru", "my_adr@yandex.ru", "пароль", :plain ) do |conn| conn.send_message "Сообщение", "my_adr@yandex.ru", "получатель@rambler.ru" end
В этом случае, на почту получатель@rambler.ru приходит письмо (без темы) от MAILER-DAEMON@ со следующим содержанием:
by mail172.rambler.ru (rmaild SMTP 1.2.41) with ESMTP id 292593804 for получатель@rambler.ru; Mon, 24 Aug 2015 11:13:46 +0300 Received: from forward22m.cmail.yandex.net (forward22m.cmail.yandex.net [5.255.216.16])
by mx2.mail.rambler.ru (Postfix) with ESMTP id 65FF15CA8 for <получатель@rambler.ru>; Mon, 24 Aug 2015 11:13:46 +0300 (MSK) Received: from smtp3m.mail.yandex.net (smtp3m.mail.yandex.net [IPv6:2a02:6b8:0:2519::125])
by forward22m.cmail.yandex.net (Yandex) with ESMTP id 488F18046B for <получатель@rambler.ru>; Mon, 24 Aug 2015 11:13:46 +0300 (MSK) Received: from smtp3m.mail.yandex.net (localhost [127.0.0.1])
by smtp3m.mail.yandex.net (Yandex) with ESMTP id 2C1A127A05B8 for <получатель@rambler.ru>; Mon, 24 Aug 2015 11:13:46 +0300 (MSK) Received: by smtp3m.mail.yandex.net (nwsmtp/Yandex) with ESMTPSA id lnLUHk87ag-DjpWkB95; Mon, 24 Aug 2015 11:13:45 +0300 (using TLSv1 with cipher AES128-SHA (128/128 bits)) (Client certificate not present) Message-Id: <20150824111345.DjpWkB95@smtp3m.mail.yandex.net> Date: Mon, 24 Aug 2015 11:13:45 +0300 From: MAILER-DAEMON To: undisclosed-recipients:; X-Spam: yes
Вариант 2
Создание и использование рассыльщика FeedbackMailer
#app/mailers/application_mailer.rb class ApplicationMailer < ActionMailer::Base end
#app/mailers/feedback_mailer.rb class FeedbackMailer < ApplicationMailer def feedback_email mail(from: 'my_adr@yandex.ru', to: 'получатель@rambler.ru', subject: 'тема') end end
#app/controllers/feedback_info_controller.rb def feedback_send FeedbackMailer.feedback_email end
#config/environments/development.rb config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { address: 'smtp.yandex.ru', port: 587, domain: 'yandex.ru', authentication: 'plain', user_name: 'my_adr@yandex.ru', password: 'пароль', enable_starttls_auto: true }
с такими настройками ничего не происходит


Ответ

config.action_mailer.smtp_settings = { tls: true,
...
Без этого yandex не работает. Причем tls: в официальной документации нет.

понедельник, 15 октября 2018 г.

Многопоточный прием данных

Есть СМТП-сервис. Он слушает 25ый порт:
SMTP_Listener = new TcpListener(IPAddress.Any, 25); SMTP_Listener.Start();
Получается, что когда к нему шлют команды 2 и более клиентов, то они "сливаются" и получается такое (пример):
Клиент1: команда "HELLO 11111" Клиент2: команда "HELLO 22222" Клиент3: команда "HELLO 33333"
Я получаю "HELLO 11" от первого клиента, от второго- "LO 22", для третьего - "LO 3333" (например).
Подскажите, как правильно разделить чтение от нескольких клиентов?
У меня каждый клиент работает в отдельном потоке.
КОД приема сообщений от клиентов:
///

/// Считываем команду клиента /// /// private string ReadLine() { try { long lastDataTime = DateTime.Now.Ticks; ArrayList lineBuf = new ArrayList(); byte prevByte = 0;
while (true) { if (clientSocket == null) l.Write(" !!! clientSocket is NULL");
if (!clientSocket.Connected) l.Write(" !!! сокет не включен!");
if (clientSocket.Available > 0) { // Read next byte byte[] currByte = new byte[1]; int countRecieved = clientSocket.Receive(currByte, 1, SocketFlags.None);
// Count must be equal. Eg. some computers won't give byte at first read attempt if (countRecieved == 1) { lineBuf.Add(currByte[0]);
// Line found if ((prevByte == (byte) '
' && currByte[0] == (byte) '
')) { byte[] retVal = new byte[lineBuf.Count - 2]; // Remove lineBuf.CopyTo(0, retVal, 0, lineBuf.Count - 2);
return System.Text.Encoding.Default.GetString(retVal).Trim(); }
// Store byte prevByte = currByte[0]; //l.Write("prevByte = " + prevByte); //// Check if maximum length is exceeded //if (lineBuf.Count > maxLen) //{ // throw new Exception( "Maximum line length exceeded"); //}
// reset last data time lastDataTime = DateTime.Now.Ticks; //l.Write("lastDataTime = " + lastDataTime); } } else { // l.Write("clientSocket.Available: " + clientSocket.Available.ToString()); // тут всегда 0 //---- Time out stuff -----------------------// if (DateTime.Now.Ticks > lastDataTime + ((long)(60000)) * 10000) { l.Write("ERROR: Read timeout: " + (((long)(60000)) * 10000).ToString());
//clientSocket.Close(); l.Write("Сокет закрыт из-за простоя в " + (((long)(60000)) * 10000).ToString() + " м-сек.");
// throw new Exception("Read timeout"); return ""; // ????????????????????????????????????????????????????????????????????? } System.Threading.Thread.Sleep(100); //------------------------------------------// } }
} catch (Exception x) { l.Write("EROR ReadLine(): " + x.ToString()); throw new Exception(x.Message); } }
UPD:
public void Listen() { int iter = 0;
try { l.Write("***************START*******************"); l.Write("SMTP server started " + DateTime.Now.ToString());
SMTP_Listener = new TcpListener(IPAddress.Any, port); SMTP_Listener.Start();
while (true) {
//тут я определяю что у нас есть клиент clientSocket = SMTP_Listener.AcceptSocket();
_sessionId = clientSocket.GetHashCode().ToString();
_email.sessionId = Convert.ToInt32(_sessionId);
l.Write("New session: " + _sessionId);
//и в отдельный поток его Thread newClient = new Thread(StartProcessing);
l.Write("Создан поток для обработки клиента " + _sessionId); UserSessionController.AddSession( Convert.ToInt32(_sessionId ) );
newClient.Name = _sessionId; newClient.IsBackground = true; // ??? newClient.Start(); }
} catch (Exception ex) { l.Write("SMTP Listen Error: " + ex.ToString()); throw; } }


Ответ

private Socket clientSocket
у вас один общий экземпляр сокета для всех клиентов.
когда подключается новый клиент
clientSocket = SMTP_Listener.AcceptSocket();
вы выбрасываете сокет, который был открыт при подключении предыдущего клиента. В результате все потоки у вас читают из this.clientSocket, ссылающегося на сокет, открытый для последнего подключенного клиента.
Т.е. все, что прислали предыдущие клиенты, но что не успели вычитать - уходит вникуда. А все, что присылает последний клиент, рвут между собой все читающие потоки.
Вам стоит перенести код, связанный с обработкой клиента, в отдельный класс, чтобы получить отдельный экземпляр на каждого клиента:
class ClientProcessor() { private Socket clientSocket; public ClientProcessor(Socket clientSocket) { this.clientSocket = clientSocket; } string ReadLine() {....} void StartProcessing(); }
и создавать новый экземпляр для каждого подключившегося клиента:
var processor = new ClientProcessor(SMTP_Listener.AcceptSocket());
Thread newClient = new Thread(processor.StartProcessing);

понедельник, 1 октября 2018 г.

Как из скрипта на Питоне послать письмо с вложением?

Нужен простейший пример посылки письма с вложением через внешний SMTP сервер, например, smtp.yandex.ru.


Ответ

from smtplib import SMTP_SSL from email.MIMEMultipart import MIMEMultipart from email.MIMEBase import MIMEBase from email import Encoders import os
filepath = "/path/to/file" basename = os.path.basename(filepath) address = "name@server"
# Compose attachment part = MIMEBase('application', "octet-stream") part.set_payload(open(filepath,"rb").read() ) Encoders.encode_base64(part) part.add_header('Content-Disposition', 'attachment; filename="%s"' % basename)
# Compose message msg = MIMEMultipart() msg['From'] = address msg['To'] = address msg.attach(part)
# Send mail smtp = SMTP_SSL() smtp.connect('smtp.yandex.ru') smtp.login(address, 'password') smtp.sendmail(address, address, msg.as_string()) smtp.quit()