Class: Mailtrap

Inherits:
Object
  • Object
show all
Defined in:
lib/mailtrap.rb

Overview

Mailtrap creates a TCP server that listens on a specified port for SMTP clients. Accepts the connection and talks just enough of the SMTP protocol for them to deliver a message which it writes to disk.

Constant Summary collapse

VERSION =
'0.2.1'

Instance Method Summary collapse

Constructor Details

#initialize(host, port, once, msgfile) ⇒ Mailtrap

Create a new Mailtrap on the specified host:port. If once it true it will listen for one message then exit. Specify the msgdir where messages are written.



18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/mailtrap.rb', line 18

def initialize( host, port, once, msgfile )
  @host = host
  @port = port
  @once = once
  @msgfile = msgfile
  
  File.open( @msgfile, "a" ) do |file|
    file.puts "\n* Mailtrap started at #{@host}:#{port}\n"
  end
  
  service = TCPServer.new( @host, @port )
  accept( service )
end

Instance Method Details

#accept(service) ⇒ Object

Service one or more SMTP client connections



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/mailtrap.rb', line 33

def accept( service )
  while session = service.accept
    
    class << session
      def get_line
        line = gets
        line.chomp! unless line.nil?
        line          
      end
    end
    
    begin
      serve( session )
    rescue Exception => e
      puts "Erk! #{e.message}"        
    end
    
    break if @once
  end    
end

#serve(connection) ⇒ Object

Talk pidgeon-SMTP to the client to get them to hand over the message and go away.



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
# File 'lib/mailtrap.rb', line 77

def serve( connection )
  connection.puts( "220 #{@host} MailTrap ready ESTMP" )
  helo = connection.get_line # whoever they are
  puts "Helo: #{helo}"
  
  if helo =~ /^EHLO\s+/
    puts "Seen an EHLO"
    connection.puts "250-#{@host} offers just ONE extension my pretty"
    connection.puts "250 HELP"
  end
  
  # Accept MAIL FROM:
  from = connection.get_line
  connection.puts( "250 OK" )
  puts "From: #{from}"
  
  to_list = []
  
  # Accept RCPT TO: until we see DATA
  loop do
    to = connection.get_line
    break if to.nil?

    if to =~ /^DATA/
      connection.puts( "354 Start your message" )
      break
    else
      puts "To: #{to}"
      to_list << to
      connection.puts( "250 OK" )
    end
  end
  
  # Capture the message body terminated by <CR>.<CR>
  lines = []
  loop do
    line = connection.get_line
    break if line.nil? || line == "."
    lines << line
    puts "+ #{line}"
  end

  # We expect the client will go away now
  connection.puts( "250 OK" )
  connection.gets # Quit
  connection.puts "221 Seeya"
  connection.close
  puts "And we're done with that bozo!"

  write( from, to_list, lines.join( "\n" ) )
  
end

#write(from, to_list, message) ⇒ Object

Write a plain text dump of the incoming email to a text file. The file will be in the @msgdir folder and will be called smtp0001.msg, smtp0002.msg, and so on.



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/mailtrap.rb', line 57

def write( from, to_list, message )
  
  # Strip SMTP commands from To: and From:
  from.gsub!( /MAIL FROM:\s*/, "" )
  to_list = to_list.map { |to| to.gsub( /RCPT TO:\s*/, "" ) }
  
  # Append to the end of the messages file
  File.open( @msgfile, "a" ) do |file|
    file.puts "* Message begins"
    file.puts "From: #{from}"
    file.puts "To: #{to_list.join(", ")}"
    file.puts "Body:"
    file.puts message
    file.puts "\n* Message ends"
  end

end