ExchangeLogAnalyzer - OpenSource парсер журнала MS Exchange Server.
Ничто в современном мире не может обходится без рассылки рекламы - как бы мы не плевались от нее. Например, на мои почтовые ящики приходит 99,4% спама - за месяц я получил всего 8216 писем и только 46 осмысленных писем.
Надо понимать, что как бы нам не нравилась рассылка рекламы (ох а как нас загружают рекламой по телевидению!), но для отделения интернет-спама от нормальной интернет-рекламы суды используют два критерия:
- Отбор адресатов для рассылки спама осуществляется автоматически, а в нормальной рекламы надо доказывать, что отбор адресатов делал человек.
- От спама невозможно отписатся, а легальная интернет-реклама позволяет навсегда отписатся от получения рекламы.
И, поскольку эти требования я соблюдаю, то в какой-то момент я тоже добавил на свой портал сервер рассылки рекламы.
Однако почтовый протокол отличается тем, что отдельные письма (по практике) - десятки тысяч раз тыкаются из передающего SMTP-сервера в приемный SMTP-сеервер. У меня на почтовике стоит ограничение - пытаться высылать письмо в течении четырех суток. И иногда некоторые письма (скажем 2-3-4 штуки на тысячу) действительно уходят лишь на четвертые сутки!
Поэтому код возврата, который формирует почтовик, сразу после обращения к нему с сайта (или из клиента типа TheBat или Outlook) - никакого значения не имеет. Нужен итоговый код возврата отправки письма - который в конфигурации моего почтовики становится известным лишь на четвертые сутки, а у кого-то может быть и через месяц.
Именно для этого предназначен анализатор журнала работы MS Exchange Server.
Немного потыкавшись в интернете, я обнаружил, что анализатор журнала работы почтовика - это одна из самых распространенных в интернете программ. В частности, только на одном-единственном сайте sourceforge.net их выложено аж 758 штук! И количество загрузок некоторых из них, например AWStats составляет 2,1 миллиона скачиваний! И все остальные скачивания тоже в миллионах и сотнях тысяч! Например Zenoss Core - Enterprise IT Monitoring тоже более миллиона скачиваний!
Ну нет, скачивать такой простой строчный парсер - я не унижусь, решил я. И за свободный вечер я написал простенькую страничку, которая делает этот анализ результатов рассылки рекламы с помощью Exchange Server. Эту страничку я опишу здесь.
Работа этой странички осуществляется в два этапа - сначала на сайт загружается файл журанала Exchange, потом он подвергается анализу, в ходе которого результат рассылки показывается на сайте и, главное, вписывается в базу:
Структуру базы вы можете видеть на рисунке, первое поле I - Identity(1,1), второе ID - это ГУИД, остальные поля текстовые. Email - это адрес, куда мы высылаем рекламу, SMTP_Replay - это ответ почтовика, который мы записываем в базу в результате работы описываемого парсера. Tag-это тег, на основании которого рассылается реклама. Понятно, что сайтам на ASP.NET можно предлагать только программирование на ASP.NET, но никак не на Битриксе.
Поле IsBlockOnRecipient - это как раз то самое поле отписки от рекламы, если получатель рекламы кликнет на ссылку отписки в тексте рекламы, то в этом поле появляется единичка и реклама болше никогда по этому адресу не рассылается.
Как вы понимаете, основная тема - каким образом сформировать эту базу с адресами для рассылки рекламы. Ее легко формировать для рассылки предложений о порно или недвижимости, но невероятно тяжело сформировать для программирования на ASP.NET. Ведь сайтов на ASP.NET - всего 0,4%. И подавляющее большинство из них - студенческий мусор или некоммерческие проекты, не представляющие интереса для профессиональных программистов. Еще сложнее сформировать базу для предложений о хостинге. Как среди миллионов и миллиардов почтовых адресов найти те несколько человек (а в Москве на хостингах находится всего несколько тысяч серверов) - как найти среди миллиардов почтовых адресов тех, кто готов заплатить 30 тысяч в месяц за размещение выделенного сервера на хостинге? Как найти того человека, кто принимает решение? Как вы понимаете - никакой автоматический механизм не поможет отобрать такие почтовые адреса. Поэтому адреса эти вносятся в базу вручную.
Но вернемся собственно к самой популярной (!) интернет-программе - анализатору журнала. Cтраничка анализа журнала выглядит беспредельно просто:
1: <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
2: <div style="text-align:left" >
3:
4: <br /><center><h4>Анализ журнала рассылки</h4></center><br />
5:
6: <asp:Label ID="Label1" runat="server" Text="Журнал Exchange"></asp:Label><br />
7: <asp:TextBox ID="TextBox1" runat="server" Width="400px"></asp:TextBox>
8: <br />
9: <asp:Button ID="Button1" runat="server" Text="Анализ" />
10: <br />
11: <asp:Label ID="lErr1" runat="server" ForeColor="Red"></asp:Label>
12: <br />
13: <asp:Label ID="lReplay" runat="server"></asp:Label>
14: <br /><br />
15: <asp:Button ID="Button2" runat="server" Text="Новый журнал" />
16:
17: </div>
18:
19: <asp:SqlDataSource ID="SetExchangeReplay" runat="server"
20: ConnectionString="<%$ ConnectionStrings:SQLServer_ConnectionStrings %>"
21: SelectCommand="Update Reklama Set SMTP_Replay=@SMTP_Replay Where Email=@Email">
22: <SelectParameters>
23: <asp:Parameter Name="SMTP_Replay" Type="String" />
24: <asp:Parameter Name="Email" Type="String" />
25: </SelectParameters>
26: </asp:SqlDataSource>
27:
28: </asp:Content>
Записи от разных приемных серверов перемешаны, повторяются иногда тысячи раз, но в базу пишется последний ответ от приемного SMTP.
1: Partial Class ExchangeAnalize
2: Inherits System.Web.UI.Page
3:
4: Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
5: If Not Me.Page.User.Identity.IsAuthenticated Then
6: Response.Redirect("Login.aspx")
7: Exit Sub
8: End If
9: '
10: If not Roles.IsUserInRole(ConfigurationManager.AppSettings("UserAdminGroup")) Then
11: Response.Redirect("//www.vb-net.com/Default.aspx")
12: End If
13: '
14: If Not IsPostBack Then
15: TextBox1.Text = Request.QueryString("Log")
16: End If
17: End Sub
18:
19: 'Анализ журнала вида:
20: '2009-12-03 23:16:48 213.85.31.238 OutboundConnectionCommand SMTPSVC2 MAIL - 25 RCPT - TO:<gh0st@mail333.com>
21: '2009-12-03 23:16:48 213.85.31.238 OutboundConnectionResponse SMTPSVC2 MAIL - 25 - - 451+4.7.1+Greylisting+in+action,+please+come+back+in+00:01:24 0 0 61 0 22329 SMTP - - - -
22: 'Записи от разных серверов перемешаны
23: Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
24: If TextBox1.Text <> "" Then
25: Dim MailIP As New System.Collections.ArrayList
26: Dim MailTo As New System.Collections.ArrayList
27: Dim RCPT_Replay As New System.Collections.ArrayList
28: '
29: Try
30: Dim LogPath As String = Server.MapPath("Log")
31: Dim FullPath As String = System.IO.Path.Combine(LogPath, TextBox1.Text)
32: Dim RDR1 As New System.IO.StreamReader(FullPath)
33: Dim Str1 As String
34: Dim Log() As String
35: While True
36: Str1 = RDR1.ReadLine
37: If Str1 Is Nothing Then Exit While
38: Log = Str1.Split(" ")
39: If Log.Length > 10 Then
40: If Log(3) = "OutboundConnectionCommand" Then
41: If Log(8) = "RCPT" Then 'попалась команда RCPT
42: MailIP.Add(Log(2))
43: MailTo.Add(Log(10).Replace("TO:<", "").Replace(">", ""))
44: RCPT_Replay.Add("") 'Признак ожидания ответа от этого сервера
45: End If
46: ElseIf Log(3) = "OutboundConnectionResponse" Then
47: 'запись ответа
48: Dim ServerNumber As Integer = MailIP.LastIndexOf(Log(2))
49: If ServerNumber >= 0 Then
50: 'Есть ответ именно от этого сервера
51: If RCPT_Replay(ServerNumber) = "" Then
52: 'Запоминаем только первый ответ от этого сервера, поступивший после команды RCPT
53: RCPT_Replay(ServerNumber) = Log(10)
54: End If
55: End If
56: End If
57: End If
58: End While
59: 'Все, табла с ответами серверов, ответивших Exchange - готова. Уплотняем ее
60: Dim MailIP_ As New System.Collections.ArrayList
61: Dim MailTo_ As New System.Collections.ArrayList
62: Dim RCPT_Replay_ As New System.Collections.ArrayList
63: For i As Integer = 0 To MailIP.Count - 1
64: Dim NewNumber As Integer = MailTo_.LastIndexOf(MailTo(i))
65: If NewNumber = -1 Then
66: MailIP_.Add(MailIP(i))
67: MailTo_.Add(MailTo(i))
68: RCPT_Replay_.Add(RCPT_Replay(i))
69: End If
70: Next
71: 'вывод на форму
72: For i As Integer = 0 To MailIP_.Count - 1
73: lReplay.Text &= MailTo_(i) & " : " & RCPT_Replay_(i) & "<br>"
74: Next
75: 'и запись в базу
76: For i As Integer = 0 To MailIP_.Count - 1
77: SetExchangeReplay.SelectParameters("SMTP_Replay").DefaultValue = MailIP_(i) & " : " & RCPT_Replay_(i).ToString.Replace("+", " ")
78: SetExchangeReplay.SelectParameters("Email").DefaultValue = MailTo_(i)
79: SetExchangeReplay.Select(New DataSourceSelectArguments)
80: Next
81: '
82: Catch ex As Exception
83: lErr1.Text = ex.Message
84: End Try
85: End If
86: End Sub
87:
88: Protected Sub Button2_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button2.Click
89: Response.Redirect("ExchangeLoad.aspx")
90: End Sub
91: End Class
Ну а вспомогательная страничка загрузки журнала работы почтовика на сайт выглядит еще проще:
1: <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
2:
3: <div style="text-align:left" >
4:
5: <br /><center><h4>Загрузка журнала рассылки</h4></center><br />
6:
7: <asp:Label ID="Label1" runat="server" Text="Журнал Exchange"></asp:Label><br />
8: <asp:FileUpload ID="FileUpload1" runat="server" Width="400px" />
9: <br />
10: <asp:Button ID="Button1" runat="server" Text="Загрузить" />
11: <br />
12: <asp:Label ID="lErr1" runat="server" ForeColor="Red"></asp:Label>
13: </div>
14:
15: </asp:Content>
1: Partial Class ExchangeLoad
2: Inherits System.Web.UI.Page
3:
4: Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
5: If Not Me.Page.User.Identity.IsAuthenticated Then
6: Response.Redirect("Login.aspx")
7: Exit Sub
8: End If
9: '
10: If not Roles.IsUserInRole(ConfigurationManager.AppSettings("UserAdminGroup")) Then
11: Response.Redirect("//www.vb-net.com/Default.aspx")
12: End If
13: End Sub
14:
15: Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
16: If FileUpload1.FileName <> "" Then
17: Try
18: Dim LogPath As String = Server.MapPath("Log")
19: Dim LogName As String = System.IO.Path.GetFileName(FileUpload1.FileName)
20: Dim FullPath As String = System.IO.Path.Combine(LogPath, LogName)
21: If My.Computer.FileSystem.FileExists(FullPath) Then
22: My.Computer.FileSystem.DeleteFile(FullPath)
23: End If
24: FileUpload1.SaveAs(FullPath)
25: Response.Redirect("ExchangeAnalize.aspx?Log=" & LogName)
26: Exit Sub
27: Catch ex As Exception
28: lErr1.Text = ex.Message
29: End Try
30: End If
31: End Sub
32: End Class
Как видите, этот код действительно проще было написать, чем эспериментировать с 758 программами примерно аналогичного назначения, опубликованными на SourceForge.NET.
Удачи!
|