-
Notifications
You must be signed in to change notification settings - Fork 17
/
inbound_emails_controller.rb
134 lines (115 loc) · 4.21 KB
/
inbound_emails_controller.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
# frozen_string_literal: true
# rubocop:disable Layout/LineLength
module ActionMailbox
# Ingests inbound emails from Amazon SES/SNS and confirms subscriptions.
#
# Subscription requests must provide the following parameters in a JSON body:
# - +Message+: Notification content
# - +MessagId+: Notification unique identifier
# - +Timestamp+: iso8601 timestamp
# - +TopicArn+: Topic identifier
# - +Type+: Type of event ("Subscription")
#
# Inbound email events must provide the following parameters in a JSON body:
# - +Message+: Notification content
# - +MessagId+: Notification unique identifier
# - +Timestamp+: iso8601 timestamp
# - +SubscribeURL+: Topic identifier
# - +TopicArn+: Topic identifier
# - +Type+: Type of event ("SubscriptionConfirmation")
#
# All requests are authenticated by validating the provided AWS signature.
#
# Returns:
#
# - <tt>204 No Content</tt> if a request is successfully processed
# - <tt>401 Unauthorized</tt> if a request does not contain a valid signature
# - <tt>404 Not Found</tt> if the Amazon ingress has not been configured
# - <tt>422 Unprocessable Entity</tt> if a request provides invalid parameters
#
# == Usage
#
# 1. Tell Action Mailbox to accept emails from Amazon SES:
#
# # config/environments/production.rb
# config.action_mailbox.ingress = :amazon
#
# 2. Configure which SNS topics will be accepted:
#
# config.action_mailbox.amazon.subscribed_topics = %w(
# arn:aws:sns:eu-west-1:123456789001:example-topic-1
# arn:aws:sns:us-east-1:123456789002:example-topic-2
# )
#
# 3. {Configure SES}[https://docs.aws.amazon.com/ses/latest/DeveloperGuide/receiving-email-notifications.html]
# to route emails through SNS.
#
# Configure SNS to send emails to +/rails/action_mailbox/amazon/inbound_emails+.
#
# If your application is found at <tt>https://example.com</tt> you would
# specify the fully-qualified URL <tt>https://example.com/rails/action_mailbox/amazon/inbound_emails</tt>.
#
# rubocop:enable Layout/LineLength
module Ingresses
module Amazon
class InboundEmailsController < ActionMailbox::BaseController
before_action :verify_authenticity
before_action :validate_topic
before_action :confirm_subscription
def create
head :bad_request unless mail.present?
ActionMailbox::InboundEmail.create_and_extract_message_id!(mail)
head :no_content
end
private
def verify_authenticity
head :bad_request unless notification.present?
head :unauthorized unless verified?
end
def confirm_subscription
return unless notification['Type'] == 'SubscriptionConfirmation'
return head :ok if confirmation_response_code&.start_with?('2')
Rails.logger.error('SNS subscription confirmation request rejected.')
head :unprocessable_entity
end
def validate_topic
return if valid_topics.include?(topic)
Rails.logger.warn("Ignoring unknown topic: #{topic}")
head :unauthorized
end
def confirmation_response_code
@confirmation_response_code ||= begin
Net::HTTP.get_response(URI(notification['SubscribeURL'])).code
end
end
def notification
@notification ||= JSON.parse(request.body.read)
rescue JSON::ParserError => e
Rails.logger.warn("Unable to parse SNS notification: #{e}")
nil
end
def verified?
verifier.authentic?(@notification.to_json)
end
def verifier
Aws::SNS::MessageVerifier.new
end
def message
@message ||= JSON.parse(notification['Message'])
end
def mail
return nil unless notification['Type'] == 'Notification'
return nil unless message['notificationType'] == 'Received'
message['content']
end
def topic
return nil unless notification.present?
notification['TopicArn']
end
def valid_topics
::Rails.configuration.action_mailbox.amazon.subscribed_topics
end
end
end
end
end