25
Aug/09
0

Are My Emails Getting Through? The Need to Monitor Email Deliverability Part II

TechOps Guy: Dave

I wanted to follow up on Jason’s post about determining if your e-mails are getting through with what we actually implemented. In order to find out whether the big guys (hotmail,gmail,AOL or earthilink) have accepted our (opt-in) e-mail message I created the following Nagios check script

?Download checkmail.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/usr/bin/ruby
 
 require '/usr/local/nagios/libexec/pop_ssl'
 require 'net/imap'
 require 'date'
 require 'date/format'
# require 'imap'
 require '/usr/lib64/ruby/gems/1.8/gems/hotmailer-1.0.1/lib/hotmailer.rb'
 require 'rubygems'
# require 'hotmailer'
 require 'getoptlong'
# require 'rdoc/usage'
 
 
class PlainAuthenticator
 
  def process(data)
    return "/0#{@user}/0#{@password}"
  end
 
  private
 
  def initialize(user, password)
    @user = user
    @password = password
  end
 
end
 
Net::IMAP.add_authenticator('PLAIN', PlainAuthenticator)
 
    opts = GetoptLong.new(
      [ '--help', '-h', GetoptLong::NO_ARGUMENT ],
      [ '--mailhost', '-m', GetoptLong::REQUIRED_ARGUMENT ],
      [ '--username', '-u', GetoptLong::REQUIRED_ARGUMENT ],
      [ '--password', '-p', GetoptLong::REQUIRED_ARGUMENT ],
      [ '--port', '-o', GetoptLong::REQUIRED_ARGUMENT ],
      [ '--search', '-s', GetoptLong::REQUIRED_ARGUMENT ],
      [ '--age', '-a', GetoptLong::REQUIRED_ARGUMENT ],
      [ '--transport', '-t', GetoptLong::REQUIRED_ARGUMENT ]
    )
 
mailhost = nil
username = nil
password = nil
searchString = nil
transport="POP3"
port = nil
age = 1
 
    opts.each do |opt, arg|
      case opt
        when '--help'
#          RDoc::usage
        when '--mailhost'
                mailhost = arg
        when '--username'
                username = arg
        when '--password'
                password = arg
        when '--search'
                searchString = arg
        when '--port'
                port = arg
        when '--transport'
                transport  = arg
          end
      end
 
i = 0
 
#Figure the out how far back we will search in a mailbox
        day = Date.today-age
        imapFormatedDate = day.strftime(fmt="%d-%b-%Y")
 
if transport == "securePOP3"
        Net::POP3.enable_ssl(OpenSSL::SSL::VERIFY_NONE)
end
 
if ((transport == "POP3") or (transport == "securePOP3"))
        pop = Net::POP3.new(mailhost, port)
        pop.start( username,password)
        if pop.mails.empty?
        else
                pop.each_mail do |m|
                        date = nil
                        m.header.each do |h|
                                if h =~ /Date/
                                        date = Date.parse(h)
                                end
                        end
                        if date >= day
                                m.pop.each do |f|
#                               puts "#{f}"
                                        if f =~ /#{searchString}/
                                                i += 1
                                        end
                                end
                        end
                end
        end
 
        pop.finish
end
 
if transport == "IMAP"
        imap = Net::IMAP.new(mailhost)
        imap.login(username, password)
        messages = imap.status("inbox", ["MESSAGES"])
        if messages["MESSAGES"] >= 1
                imap.select('INBOX')
                imap.search(["SINCE", imapFormatedDate]).each do |message_id|
                        msg = imap.fetch(message_id, "(UID RFC822.SIZE ENVELOPE BODY[TEXT])")[0]
                        body = msg.attr["BODY[TEXT]"]
        #               puts "#{body}"
                        envelope  = imap.fetch(message_id, "ENVELOPE")[0].attr["ENVELOPE"]
                        if (envelope.subject =~ /#{searchString}/) or  (body =~ /#{searchString}/)
        #           puts "#{envelope.from[0].name}: \t#{envelope.subject}"
                                i += 1
                        end
                        imap.store(message_id, "+FLAGS", [:Deleted])
                end
                imap.logout
        end
end
 
if transport == "hotmail"
        hotty = Hotmailer.new(username, password) 
        hotty.login
 
        messages = hotty.messages
        messages.each do |f|
                tempdate = f.date+" 2007"
                tempdate.gsub!(/(.*)( )(.*)/,'\1 \3')
                date = Date.parse(tempdate)
                if date >= day
                        if (f.subject =~ /#{searchString}/) or  (f.body =~ /#{searchString}/)
                                i += 1
                        end
                end
        end
 
 
end
 
if i >= 1
        puts "Found #{i} Messages matching  \"#{searchString}\""
        exit(anInteger=0)
else 
        puts "No Messages matching \"#{searchString}\"" 
        exit(anInteger=2)
end

The script should be fairly useful even today with exception of checking hotmail, since I originally wrote this hotmail has redesigned their interface break the hotmailer module I found which screen scraped the site.

So good luck and I hope your properly opted in mail is getting through.

4
Aug/09
0

Making RRD output readable

TechOps Guy: Dave

I have been doing a lot of work lately with creating new data points to monitor with cacti and when trouble shooting why a new data point is not working I have been running into a bit of an issue.  I can see what my script is handing to the cacti poller, I can see what cacti is putting in the RRD file (with increased logging), but I can’t easily see what RRD has done with that data before handing off to cacti.  By default RRD store’s the time stamps in Epoch Time (seconds since midnight on Jan 1st, 1970) and data in scientific notation. Now, I don’t know about you, but I can’t read either of those without some help so here is my little Ruby script helper

?Download readRRD.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/usr/bin/env ruby
# Author: W. David Nash III
# Version 0.1
# August 3, 2009
 
count = 0
STDIN.each do|l|
 
        count += 1
 
        printf("%-3i | ",count)
 
        if !l.match(/^\d+/)
                header = l.to_s.split
        else
 
                (td, data) = l.split(/:/).map
                time = Time.at(td.to_i)
                printf("%s:", time.strftime("%Y-%m-%d %H:%M:%S"))
 
                data.to_s.split.map do |d|
                        if (d.eql? "nan") then d = "0.00" end
                        printf(" | %20.2f", d.chomp)
                end
        end
 
        if(count == 1)
                printf("%20s", "Time")
                header.each do |h|
                        printf(" | %20s",h)
                end
        end
        puts "\n"
end

and you use it like so

rrdtool fetch rra/<RRD FILE NAME>.rrd AVERAGE -s -1h -r 60  | ./readRRD.rb

and here is some sample output

1   |                 Time |   Heap_Mem_Committed |         Heap_Mem_Max |        Heap_Mem_Used | Non_Heap_Mem_Commit |    Non_Heap_Mem_Init |     Non_Heap_Mem_Max |    Non_Heap_Mem_Used |             CPU_TIME |            User_Time |         Thread_Count |    Peak_Thread_Count |        Heap_Mem_Init
2   |
3   | 2009-08-03 13:18:00: |         213295104.00 |         532742144.00 |         130720632.67 |          36405248.00 |          12746752.00 |         100663296.00 |          36383328.00 |         623333333.33 |         531666666.67 |               111.33 |               184.00 |                 0.00
4   | 2009-08-03 13:19:00: |         213295104.00 |         532742144.00 |         132090801.60 |          36405248.00 |          12746752.00 |         100663296.00 |          36383328.00 |        1818000000.00 |        1704000000.00 |               111.80 |               184.00 |                 0.00
5   | 2009-08-03 13:20:00: |         213295104.00 |         532742144.00 |         122721880.67 |          36405248.00 |          12746752.00 |         100663296.00 |          36383328.00 |        2186666666.70 |        2057500000.00 |               112.92 |               184.00 |                 0.00