-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsend.lua
323 lines (278 loc) · 10.2 KB
/
send.lua
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
--[[ *************************************** ]]--
-- SEND.LUA
-- A basic policy file for KumoMTA to use for sending
-- to any domain without restriction
-- WARNING: This is configured to only send from localhost.
-- Relaying from generators to the public internet requires
-- additional configuration.
--[[ *************************************** ]]--
-- This require statement is needed in any script passed to KumoMTA.
-- Includes from this policy script will not need this declared again.
local kumo = require 'kumo'
-- CALLED ON STARTUP, ALL ENTRIES WITHIN init REQUIRE A REFRESH WHEN CHANGED.
kumo.on('init', function()
-- Define the default "data" spool location; this is where
-- message bodies will be stored.
-- See https://docs.kumomta.com/userguide/configuration/spool/
kumo.define_spool {
name = 'data',
path = '/var/spool/kumomta/data',
kind = 'RocksDB',
}
-- Define the default "meta" spool location; this is where
-- message envelope and metadata will be stored.
kumo.define_spool {
name = 'meta',
path = '/var/spool/kumomta/meta',
kind = 'RocksDB',
}
-- Configure logging to local disk. Separating spool and logs to separate
-- disks helps reduce IO load and can help performance.
-- See https://docs.kumomta.com/userguide/configuration/logging/
kumo.configure_local_logs {
log_dir = '/var/log/kumomta',
headers = { 'Subject', 'X-Customer-ID' },
}
-- Configure bounce classification.
-- See https://docs.kumomta.com/userguide/configuration/bounce/
kumo.configure_bounce_classifier {
files = {
'/opt/kumomta/share/bounce_classifier/iana.toml',
},
}
-- Configure HTTP Listeners for injection and management APIs.
-- See https://docs.kumomta.com/userguide/configuration/httplisteners/
kumo.start_http_listener {
listen = '0.0.0.0:8000',
-- allowed to access any http endpoint without additional auth
trusted_hosts = { '127.0.0.1', '::1' },
}
kumo.start_http_listener {
use_tls = true,
listen = '0.0.0.0:8001',
-- allowed to access any http endpoint without additional auth
trusted_hosts = { '127.0.0.1', '::1' },
}
-- Define an SMTP listener. Can be used multiple times with different
-- parameters to define multiple listeners!
-- See https://docs.kumomta.com/userguide/configuration/smtplisteners/
kumo.start_esmtp_listener {
listen = '0.0.0.0:25',
-- override the default set of relay hosts
relay_hosts = { '127.0.0.1', '192.168.1.0/24' },
-- Configure the domains that are allowed for outbound & inbound relay,
-- Out-Of-Band bounces, and Feedback Loop Reports.
-- See https://docs.kumomta.com/userguide/configuration/domains/
domains = {
['examplecorp.com'] = {
-- allow relaying mail from any source, so long as it is
-- addressed to examplecorp.com, for inbound mail.
relay_to = false,
},
['send.examplecorp.com'] = {
-- relay to anywhere, so long as the sender domain is
-- send.examplecorp.com and the connected peer matches one of the
-- listed CIDR blocks, helps prevent abuse by less trusted peers.
relay_from = { '10.0.0.0/24' },
},
['bounce.examplecorp.com'] = {
-- accept and log OOB bounce reports sent to bounce.examplecorp.com
log_oob = true,
},
['fbl.examplecorp.com'] = {
-- accept and log ARF feedback reports sent to fbl.examplecorp.com
log_arf = true,
},
},
}
-- Add an IPv6 Listener
kumo.start_esmtp_listener {
listen = '[::]:25',
relay_hosts = { '::1' },
}
-- Configure the sending IP addresses that will be used by KumoMTA to
-- connect to remote systems. Note that defining sources and pools does
-- nothing without some form of policy in effect to assign messages to
-- the source pools you have defined.
-- See https://docs.kumomta.com/userguide/configuration/sendingips/
kumo.define_egress_source {
name = 'ip-1',
source_address = '172.31.30.241',
ehlo_domain = 'mta1.examplecorp.com',
}
--[[
kumo.define_egress_source {
name = 'ip-2',
source_address = '10.0.0.2',
ehlo_domain = 'mta2.examplecorp.com',
}
]]--
--[[
-- IPv6 is also supported.
kumo.define_egress_source {
name = 'ip-3',
source_address = '2001:db8:3333:4444:5555:6666:7777:8888',
ehlo_domain = 'mta3.examplecorp.com',
}
]]--
kumo.define_egress_pool {
name = 'TenantOne',
entries = {
{ name = 'ip-2' },
-- { name = 'ip-3' },
},
}
--[[
kumo.define_egress_pool {
name = 'TenantTwo',
entries = {
{ name = 'ip-1' },
{ name = 'ip-2' },
},
}
]]--
-- Use shared throttles rather than in-process throttles, do not enable
-- without first installing and configuring redis.
-- See https://docs.kumomta.com/reference/kumo/configure_redis_throttles/
-- kumo.configure_redis_throttles { node = 'redis://127.0.0.1/' }
end) -- END OF THE INIT EVENT
-- Configure traffic shaping, typically on a global basis for each
-- destination domain. Throttles will apply on a per-ip basis.
-- See https://docs.kumomta.com/userguide/configuration/trafficshaping/
-- Throttles are part of an egress path, which is a combination of source
-- IP (egress_source) and destination. While an individual message will have
-- a named destination domain, queues are defined by using a site_name, which
-- is a pattern string that represents all MXes for the destination domain,
-- such as (alt1|alt2|alt3|alt4)?.gmail-smtp-in.l.google.com
-- This means that we configure throttles at the site_name level, which we
-- can map from the recipient domain name. This example stores throttle
-- configuration in a pair of lua tables that contain either the destination
-- domain, or the site name, depending on whether we expect the domain to
-- have a single domain name for all MX records, or to roll up many domains.
-- For each domain in the table, render the site name for lookup.
-- This will populate the MX_ROLLUP table with the correct queue identifiers
-- for all domains that are hosted by that top level domain. Note we're just
-- listing one top-level domain, not every possible MX pattern.
-- Once lookup is done, the table will look similar to this:
-- local MX_ROLLUP = {
-- ["gmail.com"] = "(alt1|alt2|alt3|alt4)?.gmail-smtp-in.l.google.com",
-- ["yahoo.com"] = "(mta5|mta6|mta7).am0.yahoodns.net"
-- }
local MX_ROLLUP = {}
for _, domain in ipairs { 'gmail.com', 'yahoo.com', 'outlook.com' } do
MX_ROLLUP[domain] = kumo.dns.lookup_mx(domain).site_name
end
-- Global domain default traffic shaping rules.
-- This table is keyed by either site name or domain name.
-- Site names are looked up first, then domain names.
local SHAPE_BY_DOMAIN = {
[MX_ROLLUP['gmail.com']] = {
connection_limit = 3,
max_deliveries_per_connection = 50,
},
[MX_ROLLUP['outlook.com']] = {
connection_limit = 10,
},
[MX_ROLLUP['yahoo.com']] = {
connection_limit = 10,
max_deliveries_per_connection = 20,
},
['comcast.net'] = {
connection_limit = 2,
max_deliveries_per_connection = 100,
max_message_rate = '1/second',
},
}
-- Per IP/Domain traffic shaping rules.
-- This table is keyed by the tuple of (site_name, source) or (domain, source).
-- Site names are looked up first, then domain names.
-- Values override/overlay those in SHAPE_BY_DOMAIN.
local SHAPE_BY_SOURCE = {
[{ MX_ROLLUP['gmail.com'], 'ip-1' }] = {
max_message_rate = '1000/hr',
},
[{ 'comcast.net', 'ip-2' }] = {
max_message_rate = '10/second',
},
}
-- Helper function that merges the values from `src` into `dest`
function merge_into(src, dest)
for k, v in pairs(src) do
dest[k] = v
end
end
kumo.on('get_egress_path_config', function(domain, egress_source, site_name)
-- resolve parameters first based on the site, if any,
-- then based on the domain, if any,
-- otherwise use the system defaults
local domain_params = SHAPE_BY_DOMAIN[site_name]
or SHAPE_BY_DOMAIN[domain]
or {}
local source_params = SHAPE_BY_SOURCE[{ site_name, egress_source }]
or SHAPE_BY_SOURCE[{ domain, egress_source }]
or {}
-- compose the source params over the domain params
local params = {}
merge_into(domain_params, params)
merge_into(source_params, params)
return kumo.make_egress_path(params)
end)
-- Configure queue management settings. These are not throttles, but instead
-- how messages flow through the queues. This example assigns pool based
-- on tenant name, and customized message expiry for a specific tenant.
-- See https://docs.kumomta.com/userguide/configuration/queuemanagement/
local TENANT_PARAMS = {
TenantOne = {
max_age = '5 minutes',
},
}
kumo.on('get_queue_config', function(domain, tenant, campaign)
local params = {
egress_pool = tenant,
}
merge_into(TENANT_PARAMS[tenant] or {}, params)
return kumo.make_queue_config(params)
end)
-- Configure DKIM signing. In this case we use a simple approach of a path
-- defined by tokens, with each domain configured in the definition. This is
-- executed whether the message arrived by SMTP or API.
-- See https://docs.kumomta.com/userguide/configuration/dkim/
--[[ Commented out for now...
-- Edit this table to add more signing domains and their selector.
local DKIM_CONFIG = {
['examplecorp.com'] = 'dkim1024',
['kumocorp.com'] = 's1024',
}
function dkim_sign(msg)
local sender_domain = msg:from_header().domain
local selector = DKIM_CONFIG[sender_domain]
if not selector then
return false -- DON'T SIGN WITHOUT A VALID SELECTOR
end
local signer = kumo.dkim.rsa_sha256_signer {
domain = sender_domain,
selector = selector,
headers = { 'From', 'To', 'Subject' },
key = string.format(
'/opt/kumomta/etc/dkim/%s/%s.key',
sender_domain,
selector
),
}
msg:dkim_sign(signer)
end
]]--
kumo.on('smtp_server_message_received', function(msg)
-- Assign tenant based on X-Tenant header.
local tenant = msg:get_first_named_header_value('x-virtual-mta') or 'default'
msg:set_meta('tenant',tenant)
end
--[[
-- SIGNING MUST COME LAST OR YOU COULD BREAK YOUR DKIM SIGNATURES
dkim_sign(msg)
end)
]]--
kumo.on('http_message_generated', function(msg)
-- Accept and discard all messages
msg:set_meta('queue', 'null')
end)