actionmailbox 0.1.0 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (152) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -0
  3. data/{LICENSE → MIT-LICENSE} +1 -1
  4. data/README.md +2 -267
  5. data/app/controllers/action_mailbox/base_controller.rb +23 -32
  6. data/app/controllers/action_mailbox/ingresses/mailgun/inbound_emails_controller.rb +88 -84
  7. data/app/controllers/action_mailbox/ingresses/mandrill/inbound_emails_controller.rb +64 -60
  8. data/app/controllers/action_mailbox/ingresses/postmark/inbound_emails_controller.rb +62 -0
  9. data/app/controllers/action_mailbox/ingresses/relay/inbound_emails_controller.rb +65 -0
  10. data/app/controllers/action_mailbox/ingresses/sendgrid/inbound_emails_controller.rb +51 -47
  11. data/app/controllers/rails/conductor/action_mailbox/inbound_emails_controller.rb +28 -20
  12. data/app/controllers/rails/conductor/action_mailbox/reroutes_controller.rb +15 -11
  13. data/app/controllers/rails/conductor/base_controller.rb +12 -8
  14. data/app/jobs/action_mailbox/incineration_job.rb +20 -13
  15. data/app/jobs/action_mailbox/routing_job.rb +10 -6
  16. data/app/models/action_mailbox/inbound_email.rb +43 -37
  17. data/app/models/action_mailbox/inbound_email/incineratable.rb +6 -4
  18. data/app/models/action_mailbox/inbound_email/incineratable/incineration.rb +21 -17
  19. data/app/models/action_mailbox/inbound_email/message_id.rb +22 -20
  20. data/app/models/action_mailbox/inbound_email/routable.rb +7 -5
  21. data/app/views/layouts/rails/conductor.html.erb +1 -0
  22. data/app/views/rails/conductor/action_mailbox/inbound_emails/new.html.erb +5 -0
  23. data/config/routes.rb +2 -2
  24. data/db/migrate/20180917164000_create_action_mailbox_tables.rb +6 -4
  25. data/lib/action_mailbox.rb +3 -1
  26. data/lib/action_mailbox/base.rb +100 -93
  27. data/lib/action_mailbox/callbacks.rb +3 -1
  28. data/lib/action_mailbox/engine.rb +12 -13
  29. data/lib/action_mailbox/gem_version.rb +17 -0
  30. data/lib/action_mailbox/mail_ext.rb +2 -0
  31. data/lib/action_mailbox/mail_ext/address_equality.rb +7 -3
  32. data/lib/action_mailbox/mail_ext/address_wrapping.rb +7 -3
  33. data/lib/action_mailbox/mail_ext/addresses.rb +22 -18
  34. data/lib/action_mailbox/mail_ext/from_source.rb +2 -0
  35. data/lib/action_mailbox/mail_ext/recipients.rb +7 -3
  36. data/lib/action_mailbox/{postfix_relayer.rb → relayer.rb} +18 -10
  37. data/lib/action_mailbox/router.rb +30 -26
  38. data/lib/action_mailbox/router/route.rb +34 -30
  39. data/lib/action_mailbox/routing.rb +3 -1
  40. data/lib/action_mailbox/test_case.rb +4 -0
  41. data/lib/action_mailbox/test_helper.rb +17 -11
  42. data/lib/action_mailbox/version.rb +8 -1
  43. data/lib/rails/generators/installer.rb +10 -0
  44. data/lib/rails/generators/mailbox/USAGE +12 -0
  45. data/lib/rails/generators/mailbox/mailbox_generator.rb +32 -0
  46. data/lib/{templates/mailboxes/application_mailbox.rb → rails/generators/mailbox/templates/application_mailbox.rb.tt} +1 -1
  47. data/lib/rails/generators/mailbox/templates/mailbox.rb.tt +4 -0
  48. data/lib/rails/generators/test_unit/mailbox_generator.rb +20 -0
  49. data/lib/rails/generators/test_unit/templates/mailbox_test.rb.tt +11 -0
  50. data/lib/tasks/ingress.rake +53 -5
  51. data/lib/tasks/install.rake +1 -1
  52. metadata +64 -236
  53. data/.gitignore +0 -2
  54. data/Gemfile +0 -8
  55. data/Gemfile.lock +0 -159
  56. data/Rakefile +0 -27
  57. data/actionmailbox.gemspec +0 -27
  58. data/app/controllers/action_mailbox/ingresses/amazon/inbound_emails_controller.rb +0 -50
  59. data/app/controllers/action_mailbox/ingresses/postfix/inbound_emails_controller.rb +0 -55
  60. data/bin/test +0 -5
  61. data/lib/templates/installer.rb +0 -4
  62. data/test/controllers/ingresses/amazon/inbound_emails_controller_test.rb +0 -20
  63. data/test/controllers/ingresses/mailgun/inbound_emails_controller_test.rb +0 -89
  64. data/test/controllers/ingresses/mandrill/inbound_emails_controller_test.rb +0 -58
  65. data/test/controllers/ingresses/postfix/inbound_emails_controller_test.rb +0 -54
  66. data/test/controllers/ingresses/sendgrid/inbound_emails_controller_test.rb +0 -44
  67. data/test/dummy/.babelrc +0 -18
  68. data/test/dummy/.gitignore +0 -3
  69. data/test/dummy/.postcssrc.yml +0 -3
  70. data/test/dummy/Rakefile +0 -6
  71. data/test/dummy/app/assets/config/manifest.js +0 -3
  72. data/test/dummy/app/assets/images/.keep +0 -0
  73. data/test/dummy/app/assets/stylesheets/application.css +0 -15
  74. data/test/dummy/app/assets/stylesheets/scaffold.css +0 -80
  75. data/test/dummy/app/channels/application_cable/channel.rb +0 -4
  76. data/test/dummy/app/channels/application_cable/connection.rb +0 -4
  77. data/test/dummy/app/controllers/application_controller.rb +0 -2
  78. data/test/dummy/app/controllers/concerns/.keep +0 -0
  79. data/test/dummy/app/helpers/application_helper.rb +0 -2
  80. data/test/dummy/app/javascript/packs/application.js +0 -0
  81. data/test/dummy/app/jobs/application_job.rb +0 -2
  82. data/test/dummy/app/mailboxes/application_mailbox.rb +0 -2
  83. data/test/dummy/app/mailboxes/messages_mailbox.rb +0 -4
  84. data/test/dummy/app/mailers/application_mailer.rb +0 -4
  85. data/test/dummy/app/models/application_record.rb +0 -3
  86. data/test/dummy/app/models/concerns/.keep +0 -0
  87. data/test/dummy/app/views/layouts/application.html.erb +0 -14
  88. data/test/dummy/app/views/layouts/mailer.html.erb +0 -13
  89. data/test/dummy/app/views/layouts/mailer.text.erb +0 -1
  90. data/test/dummy/bin/bundle +0 -3
  91. data/test/dummy/bin/rails +0 -4
  92. data/test/dummy/bin/rake +0 -4
  93. data/test/dummy/bin/setup +0 -36
  94. data/test/dummy/bin/update +0 -31
  95. data/test/dummy/bin/yarn +0 -11
  96. data/test/dummy/config.ru +0 -5
  97. data/test/dummy/config/application.rb +0 -19
  98. data/test/dummy/config/boot.rb +0 -5
  99. data/test/dummy/config/cable.yml +0 -10
  100. data/test/dummy/config/database.yml +0 -25
  101. data/test/dummy/config/environment.rb +0 -5
  102. data/test/dummy/config/environments/development.rb +0 -63
  103. data/test/dummy/config/environments/production.rb +0 -96
  104. data/test/dummy/config/environments/test.rb +0 -46
  105. data/test/dummy/config/initializers/application_controller_renderer.rb +0 -8
  106. data/test/dummy/config/initializers/assets.rb +0 -14
  107. data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
  108. data/test/dummy/config/initializers/content_security_policy.rb +0 -22
  109. data/test/dummy/config/initializers/cookies_serializer.rb +0 -5
  110. data/test/dummy/config/initializers/filter_parameter_logging.rb +0 -4
  111. data/test/dummy/config/initializers/inflections.rb +0 -16
  112. data/test/dummy/config/initializers/mime_types.rb +0 -4
  113. data/test/dummy/config/initializers/wrap_parameters.rb +0 -14
  114. data/test/dummy/config/locales/en.yml +0 -33
  115. data/test/dummy/config/puma.rb +0 -34
  116. data/test/dummy/config/routes.rb +0 -4
  117. data/test/dummy/config/spring.rb +0 -6
  118. data/test/dummy/config/storage.yml +0 -35
  119. data/test/dummy/config/webpack/development.js +0 -3
  120. data/test/dummy/config/webpack/environment.js +0 -3
  121. data/test/dummy/config/webpack/production.js +0 -3
  122. data/test/dummy/config/webpack/test.js +0 -3
  123. data/test/dummy/config/webpacker.yml +0 -65
  124. data/test/dummy/db/migrate/20180208205311_create_action_mailroom_tables.rb +0 -11
  125. data/test/dummy/db/migrate/20180212164506_create_active_storage_tables.active_storage.rb +0 -26
  126. data/test/dummy/db/schema.rb +0 -43
  127. data/test/dummy/lib/assets/.keep +0 -0
  128. data/test/dummy/log/.keep +0 -0
  129. data/test/dummy/package.json +0 -11
  130. data/test/dummy/public/404.html +0 -67
  131. data/test/dummy/public/422.html +0 -67
  132. data/test/dummy/public/500.html +0 -66
  133. data/test/dummy/public/apple-touch-icon-precomposed.png +0 -0
  134. data/test/dummy/public/apple-touch-icon.png +0 -0
  135. data/test/dummy/public/favicon.ico +0 -0
  136. data/test/dummy/storage/.keep +0 -0
  137. data/test/dummy/yarn.lock +0 -6071
  138. data/test/fixtures/files/welcome.eml +0 -631
  139. data/test/jobs/incineration_job_test.rb +0 -17
  140. data/test/test_helper.rb +0 -54
  141. data/test/unit/inbound_email/incineration_test.rb +0 -45
  142. data/test/unit/inbound_email/message_id_test.rb +0 -13
  143. data/test/unit/inbound_email_test.rb +0 -13
  144. data/test/unit/mail_ext/address_equality_test.rb +0 -9
  145. data/test/unit/mail_ext/address_wrapping_test.rb +0 -11
  146. data/test/unit/mail_ext/recipients_test.rb +0 -33
  147. data/test/unit/mailbox/bouncing_test.rb +0 -29
  148. data/test/unit/mailbox/callbacks_test.rb +0 -75
  149. data/test/unit/mailbox/routing_test.rb +0 -30
  150. data/test/unit/mailbox/state_test.rb +0 -49
  151. data/test/unit/postfix_relayer_test.rb +0 -90
  152. data/test/unit/router_test.rb +0 -137
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 56440a6cdfeaf77350754266fba5e3e00ab5abf8e05518b22bccd76f69c80f1a
4
- data.tar.gz: 1a3e0968725439b1b38f96f5e50c946e5b593f444946e40ed5dea94176d0ef14
3
+ metadata.gz: d73a94090d155c671b5beee6e20ef185787acb97cfda037847566d969cfaac35
4
+ data.tar.gz: d8cf0465ec49fb877f65aeaa11b4247f1039644d361da05a9f496207b0fff7f6
5
5
  SHA512:
6
- metadata.gz: d28565e5cc3851cc5a33fb93d3989f93351b2346e64c737d576b1b4d3cef41b01f92aba573e394e9d66e34ff602c9d99ac302daafa50199f84abda8c9213cb22
7
- data.tar.gz: 07ceb50601e8094c74c5217cf9546fb542682e77471161eeab7f73469826cfde43531d6a3e5731e26142eed509f2eea99381f671864337847be4ad14a9bbc1ac
6
+ metadata.gz: cc61055abaa0d10c34c37a97dcab707a89a87a31e810033832b78aae03a2212b705d1bde9fcdb05a0ad5ccd822e0989ba6fbea748ebe839671dfdacbf8f2c368
7
+ data.tar.gz: e7a2831fc8273b23ca3daf1048607f32cefc2785ad238cecc74b79379a8b4ec2350d9b73d77f42cf8e26746e57eabe161f6b685a774697f517cda1cc2f53cb83
@@ -0,0 +1,36 @@
1
+ ## Rails 6.0.0 (August 16, 2019) ##
2
+
3
+ * Fix Bcc header not being included with emails from `create_inbound_email_from` test helpers.
4
+
5
+ *jduff*
6
+
7
+
8
+ ## Rails 6.0.0.rc2 (July 22, 2019) ##
9
+
10
+ * No changes.
11
+
12
+
13
+ ## Rails 6.0.0.rc1 (April 24, 2019) ##
14
+
15
+ * No changes.
16
+
17
+
18
+ ## Rails 6.0.0.beta3 (March 11, 2019) ##
19
+
20
+ * No changes.
21
+
22
+
23
+ ## Rails 6.0.0.beta2 (February 25, 2019) ##
24
+
25
+ * Allow skipping incineration of processed emails.
26
+
27
+ This can be done by setting `config.action_mailbox.incinerate` to `false`.
28
+
29
+ *Pratik Naik*
30
+
31
+
32
+ ## Rails 6.0.0.beta1 (January 18, 2019) ##
33
+
34
+ * Added to Rails.
35
+
36
+ *DHH*
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2018 Basecamp, LLC
3
+ Copyright (c) 2019 Basecamp, LLC
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,277 +1,12 @@
1
1
  # Action Mailbox
2
2
 
3
- Action Mailbox routes incoming emails to controller-like mailboxes for processing in Rails. It ships with ingresses for Amazon SES, Mailgun, Mandrill, and SendGrid. You can also handle inbound mails directly via the built-in Postfix ingress.
3
+ Action Mailbox routes incoming emails to controller-like mailboxes for processing in Rails. It ships with ingresses for Mailgun, Mandrill, Postmark, and SendGrid. You can also handle inbound mails directly via the built-in Exim, Postfix, and Qmail ingresses.
4
4
 
5
5
  The inbound emails are turned into `InboundEmail` records using Active Record and feature lifecycle tracking, storage of the original email on cloud storage via Active Storage, and responsible data handling with on-by-default incineration.
6
6
 
7
7
  These inbound emails are routed asynchronously using Active Job to one or several dedicated mailboxes, which are capable of interacting directly with the rest of your domain model.
8
8
 
9
-
10
- ## How does this compare to Action Mailer's inbound processing?
11
-
12
- Rails has long had an anemic way of [receiving emails using Action Mailer](https://guides.rubyonrails.org/action_mailer_basics.html#receiving-emails), but it was poorly flushed out, lacked cohesion with the task of sending emails, and offered no help on integrating with popular inbound email processing platforms. Action Mailbox supersedes the receiving part of Action Mailer, which will be deprecated in due course.
13
-
14
-
15
- ## Installing
16
-
17
- Assumes a Rails 5.2+ application:
18
-
19
- 1. Install the gem:
20
-
21
- ```ruby
22
- # Gemfile
23
- gem "actionmailbox", github: "rails/actionmailbox", require: "action_mailbox"
24
- ```
25
-
26
- 1. Install migrations needed for InboundEmail (and ensure Active Storage is setup)
27
-
28
- ```
29
- ./bin/rails action_mailbox:install
30
- ./bin/rails db:migrate
31
- ```
32
-
33
- ## Configuring
34
-
35
- ### Amazon SES
36
-
37
- 1. Install the [`aws-sdk-sns`](https://rubygems.org/gems/aws-sdk-sns) gem:
38
-
39
- ```ruby
40
- # Gemfile
41
- gem "aws-sdk-sns", ">= 1.9.0", require: false
42
- ```
43
-
44
- 2. Tell Action Mailbox to accept emails from SES:
45
-
46
- ```ruby
47
- # config/environments/production.rb
48
- config.action_mailbox.ingress = :amazon
49
- ```
50
-
51
- 3. [Configure SES][ses-docs] to deliver emails to your application via POST requests
52
- to `/rails/action_mailbox/amazon/inbound_emails`. If your application lived at `https://example.com`, you would specify
53
- the fully-qualified URL `https://example.com/rails/action_mailbox/amazon/inbound_emails`.
54
-
55
- [ses-docs]: https://docs.aws.amazon.com/ses/latest/DeveloperGuide/receiving-email-notifications.html
56
-
57
- ### Mailgun
58
-
59
- 1. Give Action Mailbox your [Mailgun API key][mailgun-api-key] so it can authenticate requests to the Mailgun ingress.
60
-
61
- Use `rails credentials:edit` to add your API key to your application's encrypted credentials under
62
- `action_mailbox.mailgun_api_key`, where Action Mailbox will automatically find it:
63
-
64
- ```yaml
65
- action_mailbox:
66
- mailgun_api_key: ...
67
- ```
68
-
69
- Alternatively, provide your API key in the `MAILGUN_INGRESS_API_KEY` environment variable.
70
-
71
- 2. Tell Action Mailbox to accept emails from Mailgun:
72
-
73
- ```ruby
74
- # config/environments/production.rb
75
- config.action_mailbox.ingress = :mailgun
76
- ```
77
-
78
- 3. [Configure Mailgun][mailgun-forwarding] to forward inbound emails to `/rails/action_mailbox/mailgun/inbound_emails/mime`.
79
- If your application lived at `https://example.com`, you would specify the fully-qualified URL
80
- `https://example.com/rails/action_mailbox/mailgun/inbound_emails/mime`.
81
-
82
- [mailgun-api-key]: https://help.mailgun.com/hc/en-us/articles/203380100-Where-can-I-find-my-API-key-and-SMTP-credentials-
83
- [mailgun-forwarding]: https://documentation.mailgun.com/en/latest/user_manual.html#receiving-forwarding-and-storing-messages
84
-
85
- ### Mandrill
86
-
87
- 1. Give Action Mailbox your Mandrill API key so it can authenticate requests to the Mandrill ingress.
88
-
89
- Use `rails credentials:edit` to add your API key to your application's encrypted credentials under
90
- `action_mailbox.mandrill_api_key`, where Action Mailbox will automatically find it:
91
-
92
- ```yaml
93
- action_mailbox:
94
- mandrill_api_key: ...
95
- ```
96
-
97
- Alternatively, provide your API key in the `MANDRILL_INGRESS_API_KEY` environment variable.
98
-
99
- 2. Tell Action Mailbox to accept emails from Mandrill:
100
-
101
- ```ruby
102
- # config/environments/production.rb
103
- config.action_mailbox.ingress = :mandrill
104
- ```
105
-
106
- 3. [Configure Mandrill][mandrill-routing] to route inbound emails to `/rails/action_mailbox/mandrill/inbound_emails`.
107
- If your application lived at `https://example.com`, you would specify the fully-qualified URL
108
- `https://example.com/rails/action_mailbox/mandrill/inbound_emails`.
109
-
110
- [mandrill-routing]: https://mandrill.zendesk.com/hc/en-us/articles/205583197-Inbound-Email-Processing-Overview
111
-
112
- ### Postfix
113
-
114
- 1. Tell Action Mailbox to accept emails from Postfix:
115
-
116
- ```ruby
117
- # config/environments/production.rb
118
- config.action_mailbox.ingress = :postfix
119
- ```
120
-
121
- 2. Generate a strong password that Action Mailbox can use to authenticate requests to the Postfix ingress.
122
-
123
- Use `rails credentials:edit` to add the password to your application's encrypted credentials under
124
- `action_mailbox.ingress_password`, where Action Mailbox will automatically find it:
125
-
126
- ```yaml
127
- action_mailbox:
128
- ingress_password: ...
129
- ```
130
-
131
- Alternatively, provide the password in the `RAILS_INBOUND_EMAIL_PASSWORD` environment variable.
132
-
133
- 3. [Configure Postfix][postfix-config] to pipe inbound emails to `bin/rails action_mailbox:ingress:postfix`, providing
134
- the `URL` of the Postfix ingress and the `INGRESS_PASSWORD` you previously generated. If your application lived at
135
- `https://example.com`, the full command would look like this:
136
-
137
- ```
138
- URL=https://example.com/rails/action_mailbox/postfix/inbound_emails INGRESS_PASSWORD=... bin/rails action_mailbox:ingress:postfix
139
- ```
140
-
141
- [postfix-config]: https://serverfault.com/questions/258469/how-to-configure-postfix-to-pipe-all-incoming-email-to-a-script
142
-
143
- ### SendGrid
144
-
145
- 1. Tell Action Mailbox to accept emails from SendGrid:
146
-
147
- ```ruby
148
- # config/environments/production.rb
149
- config.action_mailbox.ingress = :sendgrid
150
- ```
151
-
152
- 2. Generate a strong password that Action Mailbox can use to authenticate requests to the SendGrid ingress.
153
-
154
- Use `rails credentials:edit` to add the password to your application's encrypted credentials under
155
- `action_mailbox.ingress_password`, where Action Mailbox will automatically find it:
156
-
157
- ```yaml
158
- action_mailbox:
159
- ingress_password: ...
160
- ```
161
-
162
- Alternatively, provide the password in the `RAILS_INBOUND_EMAIL_PASSWORD` environment variable.
163
-
164
- 3. [Configure SendGrid Inbound Parse][sendgrid-config] to forward inbound emails to
165
- `/rails/action_mailbox/sendgrid/inbound_emails` with the username `actionmailbox` and the password you previously
166
- generated. If your application lived at `https://example.com`, you would configure SendGrid with the following URL:
167
-
168
- ```
169
- https://actionmailbox:PASSWORD@example.com/rails/action_mailbox/sendgrid/inbound_emails
170
- ```
171
-
172
- **⚠️ Note:** When configuring your SendGrid Inbound Parse webhook, be sure to check the box labeled **“Post the raw,
173
- full MIME message.”** Action Mailbox needs the raw MIME message to work.
174
-
175
- [sendgrid-config]: https://sendgrid.com/docs/for-developers/parsing-email/setting-up-the-inbound-parse-webhook/
176
-
177
-
178
- ## Examples
179
-
180
- Configure basic routing:
181
-
182
- ```ruby
183
- # app/models/message.rb
184
- class ApplicationMailbox < ActionMailbox::Base
185
- routing /^save@/i => :forwards
186
- routing /@replies\./i => :replies
187
- end
188
- ```
189
-
190
- Then setup a mailbox:
191
-
192
- ```ruby
193
- # app/mailboxes/forwards_mailbox.rb
194
- class ForwardsMailbox < ApplicationMailbox
195
- # Callbacks specify prerequisites to processing
196
- before_processing :require_forward
197
-
198
- def process
199
- if forwarder.buckets.one?
200
- record_forward
201
- else
202
- stage_forward_and_request_more_details
203
- end
204
- end
205
-
206
- private
207
- def require_forward
208
- unless message.forward?
209
- # Use Action Mailers to bounce incoming emails back to sender – this halts processing
210
- bounce_with Forwards::BounceMailer.missing_forward(
211
- inbound_email, forwarder: forwarder
212
- )
213
- end
214
- end
215
-
216
- def forwarder
217
- @forwarder ||= Person.where(email_address: mail.from)
218
- end
219
-
220
- def record_forward
221
- forwarder.buckets.first.record \
222
- Forward.new forwarder: forwarder, subject: message.subject, content: mail.content
223
- end
224
-
225
- def stage_forward_and_request_more_details
226
- Forwards::RoutingMailer.choose_project(mail).deliver_now
227
- end
228
- end
229
- ```
230
-
231
- ## Incineration of InboundEmails
232
-
233
- By default, an InboundEmail that has been successfully processed will be incinerated after 30 days. This ensures you're not holding on to people's data willy-nilly after they may have canceled their accounts or deleted their content. The intention is that after you've processed an email, you should have extracted all the data you needed and turned it into domain models and content on your side of the application. The InboundEmail simply stays in the system for the extra time to provide debugging and forensics options.
234
-
235
- The actual incineration is done via the `IncinerationJob` that's scheduled to run after `config.action_mailbox.incinerate_after` time. This value is by default set to `30.days`, but you can change it in your production.rb configuration. (Note that this far-future incineration scheduling relies on your job queue being able to hold jobs for that long.)
236
-
237
-
238
- ## Working with Action Mailbox in development
239
-
240
- It's helpful to be able to test incoming emails in development without actually sending and receiving real emails. To accomplish this, there's a conductor controller mounted at `/rails/conductor/action_mailbox/inbound_emails`, which gives you an index of all the InboundEmails in the system, their state of processing, and a form to create a new InboundEmail as well.
241
-
242
-
243
- ## Testing mailboxes
244
-
245
- Example:
246
-
247
- ```ruby
248
- class ForwardsMailboxTest < ActionMailbox::TestCase
249
- test "directly recording a client forward for a forwarder and forwardee corresponding to one project" do
250
- assert_difference -> { people(:david).buckets.first.recordings.count } do
251
- receive_inbound_email_from_mail \
252
- to: 'save@example.com',
253
- from: people(:david).email_address,
254
- subject: "Fwd: Status update?",
255
- body: <<~BODY
256
- --- Begin forwarded message ---
257
- From: Frank Holland <frank@microsoft.com>
258
-
259
- What's the status?
260
- BODY
261
- end
262
-
263
- recording = people(:david).buckets.first.recordings.last
264
- assert_equal people(:david), recording.creator
265
- assert_equal "Status update?", recording.forward.subject
266
- assert_match "What's the status?", recording.forward.content.to_s
267
- end
268
- end
269
- ```
270
-
271
-
272
- ## Development road map
273
-
274
- Action Mailbox is destined for inclusion in Rails 6, which is due to be released some time in 2019. We will refine the framework in this separate rails/actionmailbox repository until we're ready to promote it via a pull request to rails/rails.
9
+ You can read more about Action Mailbox in the [Action Mailbox Basics](https://edgeguides.rubyonrails.org/action_mailbox_basics.html) guide.
275
10
 
276
11
  ## License
277
12
 
@@ -1,43 +1,34 @@
1
- # The base class for all Active Mailbox ingress controllers.
2
- class ActionMailbox::BaseController < ActionController::Base
3
- skip_forgery_protection
1
+ # frozen_string_literal: true
4
2
 
5
- def self.prepare
6
- # Override in concrete controllers to run code on load.
7
- end
3
+ module ActionMailbox
4
+ # The base class for all Action Mailbox ingress controllers.
5
+ class BaseController < ActionController::Base
6
+ skip_forgery_protection if default_protect_from_forgery
8
7
 
9
- before_action :ensure_configured
8
+ before_action :ensure_configured
10
9
 
11
- private
12
- def ensure_configured
13
- unless ActionMailbox.ingress == ingress_name
14
- head :not_found
10
+ private
11
+ def ensure_configured
12
+ unless ActionMailbox.ingress == ingress_name
13
+ head :not_found
14
+ end
15
15
  end
16
- end
17
-
18
- def ingress_name
19
- self.class.name.remove(/\AActionMailbox::Ingresses::/, /::InboundEmailsController\z/).underscore.to_sym
20
- end
21
-
22
16
 
23
- def authenticate_by_password
24
- if password.present?
25
- http_basic_authenticate_or_request_with username: "actionmailbox", password: password, realm: "Action Mailbox"
26
- else
27
- raise ArgumentError, "Missing required ingress credentials"
17
+ def ingress_name
18
+ self.class.name.remove(/\AActionMailbox::Ingresses::/, /::InboundEmailsController\z/).underscore.to_sym
28
19
  end
29
- end
30
20
 
31
- def password
32
- Rails.application.credentials.dig(:action_mailbox, :ingress_password) || ENV["RAILS_INBOUND_EMAIL_PASSWORD"]
33
- end
34
21
 
22
+ def authenticate_by_password
23
+ if password.present?
24
+ http_basic_authenticate_or_request_with name: "actionmailbox", password: password, realm: "Action Mailbox"
25
+ else
26
+ raise ArgumentError, "Missing required ingress credentials"
27
+ end
28
+ end
35
29
 
36
- # TODO: Extract to ActionController::HttpAuthentication
37
- def http_basic_authenticate_or_request_with(username:, password:, realm: nil)
38
- authenticate_or_request_with_http_basic(realm || "Application") do |given_username, given_password|
39
- ActiveSupport::SecurityUtils.secure_compare(given_username, username) &
40
- ActiveSupport::SecurityUtils.secure_compare(given_password, password)
30
+ def password
31
+ Rails.application.credentials.dig(:action_mailbox, :ingress_password) || ENV["RAILS_INBOUND_EMAIL_PASSWORD"]
41
32
  end
42
- end
33
+ end
43
34
  end
@@ -1,99 +1,103 @@
1
- # Ingests inbound emails from Mailgun. Requires the following parameters:
2
- #
3
- # - +body-mime+: The full RFC 822 message
4
- # - +timestamp+: The current time according to Mailgun as the number of seconds passed since the UNIX epoch
5
- # - +token+: A randomly-generated, 50-character string
6
- # - +signature+: A hexadecimal HMAC-SHA256 of the timestamp concatenated with the token, generated using the Mailgun API key
7
- #
8
- # Authenticates requests by validating their signatures.
9
- #
10
- # Returns:
11
- #
12
- # - <tt>204 No Content</tt> if an inbound email is successfully recorded and enqueued for routing to the appropriate mailbox
13
- # - <tt>401 Unauthorized</tt> if the request's signature could not be validated, or if its timestamp is more than 2 minutes old
14
- # - <tt>404 Not Found</tt> if Action Mailbox is not configured to accept inbound emails from Mailgun
15
- # - <tt>422 Unprocessable Entity</tt> if the request is missing required parameters
16
- # - <tt>500 Server Error</tt> if the Mailgun API key is missing, or one of the Active Record database,
17
- # the Active Storage service, or the Active Job backend is misconfigured or unavailable
18
- #
19
- # == Usage
20
- #
21
- # 1. Give Action Mailbox your {Mailgun API key}[https://help.mailgun.com/hc/en-us/articles/203380100-Where-can-I-find-my-API-key-and-SMTP-credentials-]
22
- # so it can authenticate requests to the Mailgun ingress.
23
- #
24
- # Use <tt>rails credentials:edit</tt> to add your API key to your application's encrypted credentials under
25
- # +action_mailbox.mailgun_api_key+, where Action Mailbox will automatically find it:
26
- #
27
- # action_mailbox:
28
- # mailgun_api_key: ...
29
- #
30
- # Alternatively, provide your API key in the +MAILGUN_INGRESS_API_KEY+ environment variable.
31
- #
32
- # 2. Tell Action Mailbox to accept emails from Mailgun:
33
- #
34
- # # config/environments/production.rb
35
- # config.action_mailbox.ingress = :mailgun
36
- #
37
- # 3. {Configure Mailgun}[https://documentation.mailgun.com/en/latest/user_manual.html#receiving-forwarding-and-storing-messages]
38
- # to forward inbound emails to `/rails/action_mailbox/mailgun/inbound_emails/mime`.
39
- #
40
- # If your application lived at <tt>https://example.com</tt>, you would specify the fully-qualified URL
41
- # <tt>https://example.com/rails/action_mailbox/mailgun/inbound_emails/mime</tt>.
42
- class ActionMailbox::Ingresses::Mailgun::InboundEmailsController < ActionMailbox::BaseController
43
- before_action :authenticate
1
+ # frozen_string_literal: true
44
2
 
45
- def create
46
- ActionMailbox::InboundEmail.create_and_extract_message_id! params.require("body-mime")
47
- end
3
+ module ActionMailbox
4
+ # Ingests inbound emails from Mailgun. Requires the following parameters:
5
+ #
6
+ # - +body-mime+: The full RFC 822 message
7
+ # - +timestamp+: The current time according to Mailgun as the number of seconds passed since the UNIX epoch
8
+ # - +token+: A randomly-generated, 50-character string
9
+ # - +signature+: A hexadecimal HMAC-SHA256 of the timestamp concatenated with the token, generated using the Mailgun API key
10
+ #
11
+ # Authenticates requests by validating their signatures.
12
+ #
13
+ # Returns:
14
+ #
15
+ # - <tt>204 No Content</tt> if an inbound email is successfully recorded and enqueued for routing to the appropriate mailbox
16
+ # - <tt>401 Unauthorized</tt> if the request's signature could not be validated, or if its timestamp is more than 2 minutes old
17
+ # - <tt>404 Not Found</tt> if Action Mailbox is not configured to accept inbound emails from Mailgun
18
+ # - <tt>422 Unprocessable Entity</tt> if the request is missing required parameters
19
+ # - <tt>500 Server Error</tt> if the Mailgun API key is missing, or one of the Active Record database,
20
+ # the Active Storage service, or the Active Job backend is misconfigured or unavailable
21
+ #
22
+ # == Usage
23
+ #
24
+ # 1. Give Action Mailbox your {Mailgun API key}[https://help.mailgun.com/hc/en-us/articles/203380100-Where-can-I-find-my-API-key-and-SMTP-credentials-]
25
+ # so it can authenticate requests to the Mailgun ingress.
26
+ #
27
+ # Use <tt>rails credentials:edit</tt> to add your API key to your application's encrypted credentials under
28
+ # +action_mailbox.mailgun_api_key+, where Action Mailbox will automatically find it:
29
+ #
30
+ # action_mailbox:
31
+ # mailgun_api_key: ...
32
+ #
33
+ # Alternatively, provide your API key in the +MAILGUN_INGRESS_API_KEY+ environment variable.
34
+ #
35
+ # 2. Tell Action Mailbox to accept emails from Mailgun:
36
+ #
37
+ # # config/environments/production.rb
38
+ # config.action_mailbox.ingress = :mailgun
39
+ #
40
+ # 3. {Configure Mailgun}[https://documentation.mailgun.com/en/latest/user_manual.html#receiving-forwarding-and-storing-messages]
41
+ # to forward inbound emails to +/rails/action_mailbox/mailgun/inbound_emails/mime+.
42
+ #
43
+ # If your application lived at <tt>https://example.com</tt>, you would specify the fully-qualified URL
44
+ # <tt>https://example.com/rails/action_mailbox/mailgun/inbound_emails/mime</tt>.
45
+ class Ingresses::Mailgun::InboundEmailsController < ActionMailbox::BaseController
46
+ before_action :authenticate
48
47
 
49
- private
50
- def authenticate
51
- head :unauthorized unless authenticated?
48
+ def create
49
+ ActionMailbox::InboundEmail.create_and_extract_message_id! params.require("body-mime")
52
50
  end
53
51
 
54
- def authenticated?
55
- if key.present?
56
- Authenticator.new(
57
- key: key,
58
- timestamp: params.require(:timestamp),
59
- token: params.require(:token),
60
- signature: params.require(:signature)
61
- ).authenticated?
62
- else
63
- raise ArgumentError, <<~MESSAGE.squish
64
- Missing required Mailgun API key. Set action_mailbox.mailgun_api_key in your application's
65
- encrypted credentials or provide the MAILGUN_INGRESS_API_KEY environment variable.
66
- MESSAGE
52
+ private
53
+ def authenticate
54
+ head :unauthorized unless authenticated?
67
55
  end
68
- end
69
-
70
- def key
71
- Rails.application.credentials.dig(:action_mailbox, :mailgun_api_key) || ENV["MAILGUN_INGRESS_API_KEY"]
72
- end
73
56
 
74
- class Authenticator
75
- attr_reader :key, :timestamp, :token, :signature
76
-
77
- def initialize(key:, timestamp:, token:, signature:)
78
- @key, @timestamp, @token, @signature = key, Integer(timestamp), token, signature
57
+ def authenticated?
58
+ if key.present?
59
+ Authenticator.new(
60
+ key: key,
61
+ timestamp: params.require(:timestamp),
62
+ token: params.require(:token),
63
+ signature: params.require(:signature)
64
+ ).authenticated?
65
+ else
66
+ raise ArgumentError, <<~MESSAGE.squish
67
+ Missing required Mailgun API key. Set action_mailbox.mailgun_api_key in your application's
68
+ encrypted credentials or provide the MAILGUN_INGRESS_API_KEY environment variable.
69
+ MESSAGE
70
+ end
79
71
  end
80
72
 
81
- def authenticated?
82
- signed? && recent?
73
+ def key
74
+ Rails.application.credentials.dig(:action_mailbox, :mailgun_api_key) || ENV["MAILGUN_INGRESS_API_KEY"]
83
75
  end
84
76
 
85
- private
86
- def signed?
87
- ActiveSupport::SecurityUtils.secure_compare signature, expected_signature
88
- end
77
+ class Authenticator
78
+ attr_reader :key, :timestamp, :token, :signature
89
79
 
90
- # Allow for 2 minutes of drift between Mailgun time and local server time.
91
- def recent?
92
- Time.at(timestamp) >= 2.minutes.ago
80
+ def initialize(key:, timestamp:, token:, signature:)
81
+ @key, @timestamp, @token, @signature = key, Integer(timestamp), token, signature
93
82
  end
94
83
 
95
- def expected_signature
96
- OpenSSL::HMAC.hexdigest OpenSSL::Digest::SHA256.new, key, "#{timestamp}#{token}"
84
+ def authenticated?
85
+ signed? && recent?
97
86
  end
98
- end
87
+
88
+ private
89
+ def signed?
90
+ ActiveSupport::SecurityUtils.secure_compare signature, expected_signature
91
+ end
92
+
93
+ # Allow for 2 minutes of drift between Mailgun time and local server time.
94
+ def recent?
95
+ Time.at(timestamp) >= 2.minutes.ago
96
+ end
97
+
98
+ def expected_signature
99
+ OpenSSL::HMAC.hexdigest OpenSSL::Digest::SHA256.new, key, "#{timestamp}#{token}"
100
+ end
101
+ end
102
+ end
99
103
  end