mailer-log 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +22 -0
- data/LICENSE +21 -0
- data/README.md +286 -0
- data/app/assets/stylesheets/mailer_log/emails.scss +18 -0
- data/app/controllers/mailer_log/admin/emails_controller.rb +34 -0
- data/app/controllers/mailer_log/admin_controller.rb +37 -0
- data/app/controllers/mailer_log/api/emails_controller.rb +88 -0
- data/app/controllers/mailer_log/api/mailers_controller.rb +15 -0
- data/app/controllers/mailer_log/application_controller.rb +7 -0
- data/app/controllers/mailer_log/assets_controller.rb +42 -0
- data/app/controllers/mailer_log/spa_controller.rb +13 -0
- data/app/controllers/mailer_log/webhooks_controller.rb +115 -0
- data/app/helpers/mailer_log/spa_helper.rb +48 -0
- data/app/jobs/mailer_log/application_job.rb +12 -0
- data/app/jobs/mailer_log/cleanup_job.rb +16 -0
- data/app/models/mailer_log/application_record.rb +7 -0
- data/app/models/mailer_log/current.rb +10 -0
- data/app/models/mailer_log/email.rb +47 -0
- data/app/models/mailer_log/event.rb +27 -0
- data/app/views/mailer_log/admin/emails/_email.html.erb +29 -0
- data/app/views/mailer_log/admin/emails/_filters.html.erb +58 -0
- data/app/views/mailer_log/admin/emails/index.html.erb +61 -0
- data/app/views/mailer_log/admin/emails/show.html.erb +132 -0
- data/app/views/mailer_log/spa/index.html.erb +21 -0
- data/config/locales/en.yml +5 -0
- data/config/routes.rb +26 -0
- data/db/schema.rb +17 -0
- data/lib/generators/mailer_log/install/install_generator.rb +33 -0
- data/lib/generators/mailer_log/install/templates/README +35 -0
- data/lib/generators/mailer_log/install/templates/create_mailer_log_tables.rb.tt +52 -0
- data/lib/generators/mailer_log/install/templates/initializer.rb.tt +33 -0
- data/lib/mailer_log/configuration.rb +33 -0
- data/lib/mailer_log/engine.rb +28 -0
- data/lib/mailer_log/mail_interceptor.rb +97 -0
- data/lib/mailer_log/mail_observer.rb +45 -0
- data/lib/mailer_log/version.rb +5 -0
- data/lib/mailer_log.rb +24 -0
- data/lib/tasks/mailer_log.rake +41 -0
- data/public/mailer_log/.vite/manifest.json +11 -0
- data/public/mailer_log/assets/index-D_66gvIL.css +1 -0
- data/public/mailer_log/assets/mailer_log-2Waj6tsV.js +46 -0
- data/public/mailer_log/index.html +13 -0
- metadata +139 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 62eb9e79690dbc8bfda9c264bdebc0d1da51e29f5df9d54d549e9fef7420cf3d
|
|
4
|
+
data.tar.gz: c9ff2c0973cdfd3514c6f9b40e102a4aa0784e21290b9b5eee0bfe51ceea9048
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 90f81eac98bbffe31bec481a156d160597a93b4e54d510c8d61784fd02aa38807723ce5cf4b6aaa622c1bd45b30be65c2a11e4a118d887757513ba67ee571cec
|
|
7
|
+
data.tar.gz: fab117cb20cb2368872faf733b6718fbffe1fafc51be4b58409d2f66a58cc632b20fe362194940de6dad562416db200de1c54c3dcc722fed803b3d9ffed6a7f0
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2024-12-14
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Initial release
|
|
13
|
+
- Rails engine for capturing all outgoing emails
|
|
14
|
+
- PostgreSQL storage for emails with full headers, body, and metadata
|
|
15
|
+
- Vue.js 3 admin UI with Tailwind CSS for browsing emails
|
|
16
|
+
- Mailgun webhook integration for delivery tracking (delivered, opened, clicked, bounced)
|
|
17
|
+
- Polymorphic `accountable` association for linking emails to business objects
|
|
18
|
+
- Configurable call stack capture for debugging
|
|
19
|
+
- JSON API for programmatic access
|
|
20
|
+
- Filter and search capabilities (by recipient, sender, subject, mailer, status, date range)
|
|
21
|
+
- Email preview with iframe rendering
|
|
22
|
+
- Delivery events timeline
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 TrafficRunners
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
# MailerLog
|
|
2
|
+
|
|
3
|
+
Rails engine for logging all outgoing emails with Mailgun webhook integration.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Automatic capture of all outgoing emails (body, headers, mailer class/action)
|
|
8
|
+
- Call stack saving for debugging (shows where the email was triggered from)
|
|
9
|
+
- Mailgun webhook integration for delivery status tracking
|
|
10
|
+
- Modern Vue 3 + Tailwind CSS admin UI
|
|
11
|
+
- Email preview in sandboxed iframe
|
|
12
|
+
- Polymorphic association with Organization/Account for filtering by organization
|
|
13
|
+
- Configurable retention period with automatic cleanup
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
### 1. Add to Gemfile
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
gem 'mailer_log'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### 2. Run install generator
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
bundle install
|
|
27
|
+
rails generate mailer_log:install
|
|
28
|
+
rails db:migrate
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
This will:
|
|
32
|
+
- Create `config/initializers/mailer_log.rb` with configuration
|
|
33
|
+
- Copy migration to `db/migrate/`
|
|
34
|
+
|
|
35
|
+
### 3. Add routes
|
|
36
|
+
|
|
37
|
+
```ruby
|
|
38
|
+
# config/routes.rb
|
|
39
|
+
Rails.application.routes.draw do
|
|
40
|
+
mount MailerLog::Engine, at: '/mailer_log'
|
|
41
|
+
end
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 4. Build the frontend (if needed)
|
|
45
|
+
|
|
46
|
+
The engine includes pre-built Vue.js frontend assets. If you need to rebuild:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# From host application
|
|
50
|
+
rake mailer_log:build_frontend
|
|
51
|
+
|
|
52
|
+
# Or directly
|
|
53
|
+
cd path/to/mailer_log/frontend
|
|
54
|
+
npm install
|
|
55
|
+
npm run build
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 5. Configure initializer
|
|
59
|
+
|
|
60
|
+
Edit `config/initializers/mailer_log.rb` to customize settings:
|
|
61
|
+
|
|
62
|
+
```ruby
|
|
63
|
+
MailerLog.configure do |config|
|
|
64
|
+
# Email retention period (default 1 year)
|
|
65
|
+
config.retention_period = 1.year
|
|
66
|
+
|
|
67
|
+
# Key for Mailgun webhook verification
|
|
68
|
+
config.webhook_signing_key = ENV['MAILGUN_WEBHOOK_SIGNING_KEY']
|
|
69
|
+
|
|
70
|
+
# Capture call stack (useful for debugging)
|
|
71
|
+
config.capture_call_stack = Rails.env.development?
|
|
72
|
+
|
|
73
|
+
# Optional: Additional authentication for admin UI
|
|
74
|
+
# config.authenticate_with do |controller|
|
|
75
|
+
# controller.send(:require_super_admin!)
|
|
76
|
+
# end
|
|
77
|
+
|
|
78
|
+
# Optional: Resolver for organization association
|
|
79
|
+
# config.resolve_accountable do |email_record|
|
|
80
|
+
# User.find_by(email: email_record.to_addresses&.first)&.organization
|
|
81
|
+
# end
|
|
82
|
+
end
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Mailgun Webhook Setup
|
|
86
|
+
|
|
87
|
+
### 1. Get Webhook Signing Key
|
|
88
|
+
|
|
89
|
+
1. Log in to [Mailgun Dashboard](https://app.mailgun.com/)
|
|
90
|
+
2. Go to **Sending** → **Webhooks**
|
|
91
|
+
3. Copy the **HTTP webhook signing key**
|
|
92
|
+
4. Add to ENV: `MAILGUN_WEBHOOK_SIGNING_KEY=your_key_here`
|
|
93
|
+
|
|
94
|
+
### 2. Configure Webhook URL
|
|
95
|
+
|
|
96
|
+
1. In Mailgun Dashboard, go to **Webhooks**
|
|
97
|
+
2. Add webhook for each event:
|
|
98
|
+
- URL: `https://your-app.com/admin/email_log/webhooks/mailgun`
|
|
99
|
+
- Events: `delivered`, `opened`, `clicked`, `bounced`, `failed`, `dropped`, `complained`
|
|
100
|
+
|
|
101
|
+
### 3. For Each Domain
|
|
102
|
+
|
|
103
|
+
If using multiple domains (white-label), configure webhooks for each.
|
|
104
|
+
|
|
105
|
+
## Usage
|
|
106
|
+
|
|
107
|
+
### Admin UI
|
|
108
|
+
|
|
109
|
+
After installation, accessible at: `/admin/email_log/admin/emails`
|
|
110
|
+
|
|
111
|
+
**Features:**
|
|
112
|
+
- List of all sent emails with pagination
|
|
113
|
+
- Filtering by: recipient, sender, subject, mailer class, status, date
|
|
114
|
+
- Email details view: headers, body preview, delivery events
|
|
115
|
+
- Call stack view (where in code the email was triggered)
|
|
116
|
+
|
|
117
|
+
### Email Statuses
|
|
118
|
+
|
|
119
|
+
| Status | Description |
|
|
120
|
+
|--------|-------------|
|
|
121
|
+
| `pending` | Email created, waiting to be sent |
|
|
122
|
+
| `sent` | Email sent to Mailgun |
|
|
123
|
+
| `delivered` | Email delivered to recipient |
|
|
124
|
+
| `opened` | Email opened (tracking pixel) |
|
|
125
|
+
| `clicked` | Link in email clicked |
|
|
126
|
+
| `bounced` | Email not delivered (hard bounce) |
|
|
127
|
+
| `complained` | Recipient marked as spam |
|
|
128
|
+
|
|
129
|
+
### Programmatic Access
|
|
130
|
+
|
|
131
|
+
```ruby
|
|
132
|
+
# Find all emails for a user
|
|
133
|
+
MailerLog::Email.recipient('user@example.com')
|
|
134
|
+
|
|
135
|
+
# Find emails by mailer class
|
|
136
|
+
MailerLog::Email.by_mailer('UsersMailer')
|
|
137
|
+
|
|
138
|
+
# Find undelivered emails
|
|
139
|
+
MailerLog::Email.by_status('bounced')
|
|
140
|
+
|
|
141
|
+
# Last 10 emails
|
|
142
|
+
MailerLog::Email.recent.limit(10)
|
|
143
|
+
|
|
144
|
+
# Emails with events
|
|
145
|
+
email = MailerLog::Email.find(id)
|
|
146
|
+
email.events.each do |event|
|
|
147
|
+
puts "#{event.event_type} at #{event.occurred_at}"
|
|
148
|
+
end
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Cleaning Up Old Records
|
|
152
|
+
|
|
153
|
+
Add to Sidekiq cron or call periodically:
|
|
154
|
+
|
|
155
|
+
```ruby
|
|
156
|
+
# Run manually
|
|
157
|
+
MailerLog::CleanupJob.perform_now
|
|
158
|
+
|
|
159
|
+
# Via Sidekiq
|
|
160
|
+
MailerLog::CleanupJob.perform_later
|
|
161
|
+
|
|
162
|
+
# In sidekiq-cron (config/schedule.yml or sidekiq.yml)
|
|
163
|
+
cleanup_mailer_log:
|
|
164
|
+
cron: '0 3 * * *' # Daily at 3:00 AM
|
|
165
|
+
class: MailerLog::CleanupJob
|
|
166
|
+
queue: low_priority
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Configuration
|
|
170
|
+
|
|
171
|
+
| Parameter | Default | Description |
|
|
172
|
+
|-----------|---------|-------------|
|
|
173
|
+
| `retention_period` | `1.year` | Email retention period |
|
|
174
|
+
| `webhook_signing_key` | `nil` | Key for Mailgun webhook verification |
|
|
175
|
+
| `capture_call_stack` | `true` | Capture call stack |
|
|
176
|
+
| `call_stack_depth` | `20` | Call stack depth |
|
|
177
|
+
| `admin_layout` | `'application'` | Layout for admin views |
|
|
178
|
+
| `per_page` | `25` | Records per page |
|
|
179
|
+
|
|
180
|
+
## Troubleshooting
|
|
181
|
+
|
|
182
|
+
### Emails Not Being Saved
|
|
183
|
+
|
|
184
|
+
1. Check that engine is included in Gemfile and bundle install was run
|
|
185
|
+
2. Check that migrations are executed: `rails db:migrate:status`
|
|
186
|
+
3. Check logs for errors in `MailerLog::MailObserver`
|
|
187
|
+
|
|
188
|
+
### Webhooks Not Working
|
|
189
|
+
|
|
190
|
+
1. Check `MAILGUN_WEBHOOK_SIGNING_KEY` in ENV
|
|
191
|
+
2. Check that URL is accessible externally (not localhost)
|
|
192
|
+
3. Check logs for signature verification errors
|
|
193
|
+
4. In Mailgun Dashboard, check webhook status (failed/success)
|
|
194
|
+
|
|
195
|
+
### Events Not Linking to Emails
|
|
196
|
+
|
|
197
|
+
1. Check that `message_id` is being saved correctly
|
|
198
|
+
2. Check that header `X-Mailer-Log-Tracking-ID` is passed to Mailgun
|
|
199
|
+
3. Webhook may arrive before email is saved — retry mechanism is used
|
|
200
|
+
|
|
201
|
+
## Frontend Development
|
|
202
|
+
|
|
203
|
+
The admin UI is built with Vue 3 + Vite + Tailwind CSS.
|
|
204
|
+
|
|
205
|
+
### Development Mode
|
|
206
|
+
|
|
207
|
+
For hot-reload during development:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
# Terminal 1: Start Rails server
|
|
211
|
+
rails server
|
|
212
|
+
|
|
213
|
+
# Terminal 2: Start Vite dev server
|
|
214
|
+
cd path/to/mailer_log/frontend
|
|
215
|
+
npm run dev
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
The Vue app will automatically use the Vite dev server at `http://localhost:5173` when assets are not built.
|
|
219
|
+
|
|
220
|
+
### Building for Production
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
rake mailer_log:build_frontend
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Built assets are stored in `public/mailer_log/assets/`.
|
|
227
|
+
|
|
228
|
+
### Frontend Structure
|
|
229
|
+
|
|
230
|
+
```
|
|
231
|
+
frontend/
|
|
232
|
+
├── src/
|
|
233
|
+
│ ├── api/ # API client functions
|
|
234
|
+
│ ├── assets/ # CSS and static assets
|
|
235
|
+
│ ├── components/ # Reusable Vue components
|
|
236
|
+
│ ├── views/ # Page components
|
|
237
|
+
│ ├── App.vue # Root component
|
|
238
|
+
│ └── main.js # Entry point
|
|
239
|
+
├── index.html # HTML template
|
|
240
|
+
├── package.json
|
|
241
|
+
├── tailwind.config.js
|
|
242
|
+
└── vite.config.js
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Customizing Components
|
|
246
|
+
|
|
247
|
+
You can override Vue components (like the navbar) to match your application's style.
|
|
248
|
+
|
|
249
|
+
1. Create an overrides directory in your host application:
|
|
250
|
+
```bash
|
|
251
|
+
mkdir -p app/javascript/mailer_log_overrides
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
2. Copy and customize the component:
|
|
255
|
+
```bash
|
|
256
|
+
cp path/to/mailer_log/frontend/src/components/AppNavbar.vue \
|
|
257
|
+
app/javascript/mailer_log_overrides/AppNavbar.vue
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
3. Build with the override path:
|
|
261
|
+
```bash
|
|
262
|
+
MAILER_LOG_OVERRIDES_PATH=/path/to/app/javascript/mailer_log_overrides \
|
|
263
|
+
rake mailer_log:build_frontend
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**Overridable components:**
|
|
267
|
+
- `AppNavbar.vue` - Header/navigation bar
|
|
268
|
+
|
|
269
|
+
Example custom navbar that matches host application style:
|
|
270
|
+
```vue
|
|
271
|
+
<template>
|
|
272
|
+
<nav class="your-app-navbar">
|
|
273
|
+
<router-link to="/">Email Log</router-link>
|
|
274
|
+
<!-- Your custom navigation items -->
|
|
275
|
+
</nav>
|
|
276
|
+
</template>
|
|
277
|
+
|
|
278
|
+
<script setup>
|
|
279
|
+
// You can import from @mailer-log/ alias to reuse engine components
|
|
280
|
+
// import StatusBadge from '@mailer-log/components/StatusBadge.vue'
|
|
281
|
+
</script>
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## License
|
|
285
|
+
|
|
286
|
+
MIT
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// MailerLog Email Views Styles
|
|
2
|
+
|
|
3
|
+
.mailer-log-email-preview {
|
|
4
|
+
width: 100%;
|
|
5
|
+
height: 500px;
|
|
6
|
+
border: 1px solid #ddd;
|
|
7
|
+
background: #fff;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.mailer-log-scrollable-content {
|
|
11
|
+
max-height: 500px;
|
|
12
|
+
overflow: auto;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.mailer-log-scrollable-content-sm {
|
|
16
|
+
max-height: 300px;
|
|
17
|
+
overflow: auto;
|
|
18
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MailerLog
|
|
4
|
+
module Admin
|
|
5
|
+
class EmailsController < MailerLog::AdminController
|
|
6
|
+
has_scope :recipient
|
|
7
|
+
has_scope :sender
|
|
8
|
+
has_scope :subject_search
|
|
9
|
+
has_scope :by_mailer, as: :mailer
|
|
10
|
+
has_scope :by_status, as: :status
|
|
11
|
+
has_scope :date_from
|
|
12
|
+
has_scope :date_to
|
|
13
|
+
|
|
14
|
+
def index
|
|
15
|
+
@emails = apply_scopes(MailerLog::Email.order(created_at: :desc))
|
|
16
|
+
.page(params[:page])
|
|
17
|
+
.per(params[:per] || 25)
|
|
18
|
+
@mailers = MailerLog::Email.distinct.pluck(:mailer_class).compact.sort
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def show
|
|
22
|
+
@email = MailerLog::Email.find(params[:id])
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def preview
|
|
26
|
+
@email = MailerLog::Email.find(params[:id])
|
|
27
|
+
# rubocop:disable Rails/OutputSafety
|
|
28
|
+
render html: @email.html_body&.html_safe, layout: false
|
|
29
|
+
# rubocop:enable Rails/OutputSafety
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MailerLog
|
|
4
|
+
class AdminController < ::AdminsController
|
|
5
|
+
prepend HasScope
|
|
6
|
+
|
|
7
|
+
# Expose main app routes to views for navbar/layout links
|
|
8
|
+
helper Rails.application.routes.url_helpers
|
|
9
|
+
|
|
10
|
+
before_action :authenticate_mailer_log!
|
|
11
|
+
|
|
12
|
+
# Make main_app proxy available in views
|
|
13
|
+
helper_method :main_app
|
|
14
|
+
|
|
15
|
+
# Override url_options to prevent main app routes from being prefixed
|
|
16
|
+
# with the engine's mount path
|
|
17
|
+
def url_options
|
|
18
|
+
script_name = request.env['SCRIPT_NAME']
|
|
19
|
+
return super unless script_name&.include?('mailer_log') || script_name&.include?('email_log')
|
|
20
|
+
|
|
21
|
+
super.merge(script_name: '')
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def authenticate_mailer_log!
|
|
27
|
+
return unless MailerLog.configuration.authenticate_with_proc
|
|
28
|
+
|
|
29
|
+
MailerLog.configuration.authenticate_with_proc.call(self)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def mailer_log_engine
|
|
33
|
+
MailerLog::Engine.routes.url_helpers
|
|
34
|
+
end
|
|
35
|
+
helper_method :mailer_log_engine
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MailerLog
|
|
4
|
+
module Api
|
|
5
|
+
class EmailsController < MailerLog::AdminController
|
|
6
|
+
skip_before_action :verify_authenticity_token, only: [:index, :show]
|
|
7
|
+
|
|
8
|
+
def index
|
|
9
|
+
emails = apply_filters(MailerLog::Email.order(created_at: :desc))
|
|
10
|
+
.page(params[:page])
|
|
11
|
+
.per(params[:per] || 25)
|
|
12
|
+
|
|
13
|
+
render json: {
|
|
14
|
+
emails: emails.map { |e| email_json(e) },
|
|
15
|
+
total_count: emails.total_count,
|
|
16
|
+
total_pages: emails.total_pages,
|
|
17
|
+
current_page: emails.current_page
|
|
18
|
+
}
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def show
|
|
22
|
+
email = MailerLog::Email.find(params[:id])
|
|
23
|
+
|
|
24
|
+
render json: {
|
|
25
|
+
email: email_json(email, include_body: true, include_events: true)
|
|
26
|
+
}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def apply_filters(scope)
|
|
32
|
+
scope = scope.recipient(params[:recipient]) if params[:recipient].present?
|
|
33
|
+
scope = scope.sender(params[:sender]) if params[:sender].present?
|
|
34
|
+
scope = scope.subject_search(params[:subject_search]) if params[:subject_search].present?
|
|
35
|
+
scope = scope.by_mailer(params[:mailer]) if params[:mailer].present?
|
|
36
|
+
scope = scope.by_status(params[:status]) if params[:status].present?
|
|
37
|
+
scope = scope.date_from(params[:date_from]) if params[:date_from].present?
|
|
38
|
+
scope = scope.date_to(params[:date_to]) if params[:date_to].present?
|
|
39
|
+
scope
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def email_json(email, include_body: false, include_events: false)
|
|
43
|
+
data = {
|
|
44
|
+
id: email.id,
|
|
45
|
+
tracking_id: email.tracking_id,
|
|
46
|
+
message_id: email.message_id,
|
|
47
|
+
mailer_class: email.mailer_class,
|
|
48
|
+
mailer_action: email.mailer_action,
|
|
49
|
+
from_address: email.from_address,
|
|
50
|
+
to_addresses: email.to_addresses,
|
|
51
|
+
cc_addresses: email.cc_addresses,
|
|
52
|
+
bcc_addresses: email.bcc_addresses,
|
|
53
|
+
subject: email.subject,
|
|
54
|
+
domain: email.domain,
|
|
55
|
+
status: email.status,
|
|
56
|
+
delivered_at: email.delivered_at,
|
|
57
|
+
opened_at: email.opened_at,
|
|
58
|
+
clicked_at: email.clicked_at,
|
|
59
|
+
bounced_at: email.bounced_at,
|
|
60
|
+
created_at: email.created_at,
|
|
61
|
+
updated_at: email.updated_at
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if include_body
|
|
65
|
+
data[:html_body] = email.html_body
|
|
66
|
+
data[:text_body] = email.text_body
|
|
67
|
+
data[:headers] = email.headers
|
|
68
|
+
data[:call_stack] = email.call_stack
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
if include_events
|
|
72
|
+
data[:events] = email.events.recent.map do |event|
|
|
73
|
+
{
|
|
74
|
+
id: event.id,
|
|
75
|
+
event_type: event.event_type,
|
|
76
|
+
occurred_at: event.occurred_at,
|
|
77
|
+
recipient: event.recipient,
|
|
78
|
+
ip_address: event.ip_address,
|
|
79
|
+
user_agent: event.user_agent
|
|
80
|
+
}
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
data
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MailerLog
|
|
4
|
+
module Api
|
|
5
|
+
class MailersController < MailerLog::AdminController
|
|
6
|
+
skip_before_action :verify_authenticity_token
|
|
7
|
+
|
|
8
|
+
def index
|
|
9
|
+
mailers = MailerLog::Email.distinct.pluck(:mailer_class).compact.sort
|
|
10
|
+
|
|
11
|
+
render json: { mailers: mailers }
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MailerLog
|
|
4
|
+
class AssetsController < ActionController::Base
|
|
5
|
+
skip_forgery_protection
|
|
6
|
+
|
|
7
|
+
def show
|
|
8
|
+
file_path = MailerLog::Engine.root.join('public', 'mailer_log', 'assets', params[:path])
|
|
9
|
+
|
|
10
|
+
if File.exist?(file_path) && file_path.to_s.start_with?(MailerLog::Engine.root.join('public', 'mailer_log').to_s)
|
|
11
|
+
content_type = content_type_for(file_path)
|
|
12
|
+
send_file file_path, type: content_type, disposition: 'inline'
|
|
13
|
+
else
|
|
14
|
+
head :not_found
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def content_type_for(file_path)
|
|
21
|
+
extension = File.extname(file_path).downcase
|
|
22
|
+
case extension
|
|
23
|
+
when '.js'
|
|
24
|
+
'application/javascript'
|
|
25
|
+
when '.css'
|
|
26
|
+
'text/css'
|
|
27
|
+
when '.map'
|
|
28
|
+
'application/json'
|
|
29
|
+
when '.svg'
|
|
30
|
+
'image/svg+xml'
|
|
31
|
+
when '.png'
|
|
32
|
+
'image/png'
|
|
33
|
+
when '.jpg', '.jpeg'
|
|
34
|
+
'image/jpeg'
|
|
35
|
+
when '.woff', '.woff2'
|
|
36
|
+
'font/woff2'
|
|
37
|
+
else
|
|
38
|
+
'application/octet-stream'
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|