Class: Tina4::DevMailbox

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(mailbox_dir: nil) ⇒ DevMailbox

Returns a new instance of DevMailbox.



13
14
15
16
# File 'lib/tina4/dev_mailbox.rb', line 13

def initialize(mailbox_dir: nil)
  @mailbox_dir = mailbox_dir || ENV["TINA4_MAILBOX_DIR"] || "data/mailbox"
  ensure_dirs
end

Instance Attribute Details

#mailbox_dirObject (readonly)

Returns the value of attribute mailbox_dir.



11
12
13
# File 'lib/tina4/dev_mailbox.rb', line 11

def mailbox_dir
  @mailbox_dir
end

Instance Method Details

#capture(to:, subject:, body:, html: false, text: nil, cc: [], bcc: [], reply_to: nil, from_address: nil, from_name: nil, attachments: []) ⇒ Object

Capture an outgoing email to the local filesystem instead of sending text: carries the plain-text alternative onto the dev path. Every framework used to drop it, so what you inspected in the mailbox was not what would have been sent -- a mailbox that shows you a different message is worse than none.



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
# File 'lib/tina4/dev_mailbox.rb', line 22

def capture(to:, subject:, body:, html: false, text: nil, cc: [], bcc: [],
            reply_to: nil, from_address: nil, from_name: nil, attachments: [])
  msg_id = SecureRandom.uuid
  timestamp = Time.now

  message = {
    id: msg_id,
    from: { name: from_name, email: from_address },
    to: normalize_recipients(to),
    cc: normalize_recipients(cc),
    bcc: normalize_recipients(bcc),
    reply_to: reply_to,
    subject: subject,
    body: body,
    text: text,
    html: html,
    attachments: store_attachments(msg_id, attachments),
    read: false,
    folder: "outbox",
    created_at: timestamp.strftime("%Y-%m-%dT%H:%M:%S.%6N%:z"),
    updated_at: timestamp.iso8601
  }

  write_message(msg_id, message)

  Tina4::Log.debug("DevMailbox captured email: #{subject} -> #{Array(to).join(', ')}")
  { success: true, message: "Email captured to dev mailbox", id: msg_id }
end

#clear(folder: nil) ⇒ Object

Clear all messages, optionally by folder



90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/tina4/dev_mailbox.rb', line 90

def clear(folder: nil)
  if folder
    load_all_messages.each do |msg|
      delete(msg[:id]) if msg[:folder] == folder
    end
  else
    messages_dir = File.join(@mailbox_dir, "messages")
    FileUtils.rm_rf(messages_dir)
    FileUtils.rm_rf(File.join(@mailbox_dir, "attachments"))
    ensure_dirs
  end
end

#count(folder: nil) ⇒ Object

Count messages by folder Returns { inbox: N, outbox: N, total: N }



123
124
125
126
127
128
129
130
131
132
133
# File 'lib/tina4/dev_mailbox.rb', line 123

def count(folder: nil)
  messages = load_all_messages
  if folder
    n = messages.count { |m| m[:folder] == folder }
    { folder.to_sym => n, total: n }
  else
    inbox_count = messages.count { |m| m[:folder] == "inbox" }
    outbox_count = messages.count { |m| m[:folder] == "outbox" }
    { inbox: inbox_count, outbox: outbox_count, total: messages.length }
  end
end

#delete(msg_id) ⇒ Object

Delete a message by ID



78
79
80
81
82
83
84
85
86
87
# File 'lib/tina4/dev_mailbox.rb', line 78

def delete(msg_id)
  path = message_path(msg_id)
  return false unless File.exist?(path)

  File.delete(path)
  # Clean up attachments directory
  att_dir = File.join(@mailbox_dir, "attachments", msg_id)
  FileUtils.rm_rf(att_dir) if Dir.exist?(att_dir)
  true
end

#inbox(limit: 50, offset: 0, folder: nil) ⇒ Object

List messages in the mailbox



52
53
54
55
56
# File 'lib/tina4/dev_mailbox.rb', line 52

def inbox(limit: 50, offset: 0, folder: nil)
  messages = load_all_messages
  messages = messages.select { |m| m[:folder] == folder } if folder
  messages.sort_by { |m| m[:created_at] || "" }.reverse[offset, limit] || []
end

#read(msg_id) ⇒ Object

Read a single message by ID



59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/tina4/dev_mailbox.rb', line 59

def read(msg_id)
  path = message_path(msg_id)
  return nil unless File.exist?(path)

  message = JSON.parse(File.read(path, encoding: "UTF-8"), symbolize_names: true)
  unless message[:read]
    message[:read] = true
    message[:updated_at] = Time.now.iso8601
    File.write(path, JSON.pretty_generate(message), encoding: "UTF-8")
  end
  message
end

#seed(count: 5) ⇒ Object

Seed the mailbox with sample messages for development



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/tina4/dev_mailbox.rb', line 104

def seed(count: 5)
  fake = Tina4::FakeData.new
  count.times do |i|
    name = fake.name
    email = fake.email(from_name: name)
    capture(
      to: "dev@localhost",
      subject: fake.sentence(words: 4 + rand(4)),
      body: Array.new(2 + rand(3)) { fake.sentence(words: 8 + rand(8)) }.join("\n\n"),
      html: i.even?,
      from_address: email,
      from_name: name
    )
  end
  Tina4::Log.info("DevMailbox seeded with #{count} messages")
end

#unread_countObject

Count unread messages



73
74
75
# File 'lib/tina4/dev_mailbox.rb', line 73

def unread_count
  load_all_messages.count { |m| m[:read] == false }
end