slack_message 2.4.0 ā†’ 3.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,387 @@
1
+ ## The Message DSL
2
+
3
+ A pretty good number of the elements available in BlockKit are usable in
4
+ SlackMessage. There are also a few elements that haven't been implemented in
5
+ the official API, but are too useful to be missing.
6
+
7
+ ### Basic Text
8
+
9
+ While BlockKit officially requires that any elements are contained within a
10
+ section element, that requirement is relaxed in SlackMessage. If you don't
11
+ specify a section, one will silently be created to encapsulate your code.
12
+ That's the secret behind the most basic messages in these docs.
13
+
14
+ ```ruby
15
+ SlackMessage.build do
16
+ text "couldn't be easier"
17
+ end
18
+
19
+ # => [{:type=>"section",
20
+ # :text=>{:type=>"mrkdwn", :text=>"couldn't be easier"}
21
+ # }]
22
+ ```
23
+
24
+ This is equivalent to the more verbose version with a declared section.
25
+
26
+ ```ruby
27
+ SlackMessage.build do
28
+ section do
29
+ text "could be easier"
30
+ end
31
+ end
32
+
33
+ # => [{:type=>"section",
34
+ # :text=>{:type=>"mrkdwn", :text=>"could be easier"}
35
+ # }]
36
+ ```
37
+
38
+ Text elements are the most basic type of element. Adding multiple text calls
39
+ will add a newline between text calls, which will cause a line break
40
+ appropriately.
41
+
42
+ ```ruby
43
+ SlackMessage.build do
44
+ text "one fish, two fish"
45
+ text "red fish, blue fish"
46
+ end
47
+
48
+ # => [{:type=>"section",
49
+ # :text=>{:type=>"mrkdwn", :text=>"one fish, two fish\nred fish, blue fish"}
50
+ # }]
51
+ ```
52
+
53
+ Slack uses a [faux-markdown syntax called
54
+ mrkdwn](https://api.slack.com/reference/surfaces/formatting#basics), which you
55
+ may be familiar with by typing in the Slack app itself. The API will
56
+ automatically render mrkdwn appropriately.
57
+
58
+ ```ruby
59
+ SlackMessage.build do
60
+ text "*Favorite Colors*"
61
+ text "_John_: ~red~ actually blue."
62
+ end
63
+
64
+ # => [{:type=>"section",
65
+ # :text=>{:type=>"mrkdwn", :text=>"*Favorite Colors*\n_John_: ~red~ actually blue."}}]
66
+ ```
67
+
68
+ Rendering emoji in messages is possible using either a) real unicode emoji in
69
+ your message, or b) using the `:emojiname:` syntax, which supports any emoji
70
+ that would work in your Slack app itself, including custom emoji.
71
+
72
+ ```ruby
73
+ SlackMessage.build do
74
+ text ":shipit_squirrel:šŸš€ time to gooo :tada:"
75
+ end
76
+
77
+ # => [{:type=>"section",
78
+ # :text=>{:type=>"mrkdwn", :text=>":shipit_squirrel:šŸš€ time to gooo :tada:"}
79
+ # }]
80
+ ```
81
+
82
+ To add a link using Slack's non-markdown link syntax, use the `link` helper
83
+ method interpolated into a text element. Using the `link` helper as its own
84
+ element won't work, as the method simply returns a string that has to be
85
+ included into a text element specifically.
86
+
87
+ ```ruby
88
+ SlackMessage.build do
89
+ text "Your #{link('build', 'https://google.com')} is ready."
90
+ end
91
+
92
+ # => [{:type=>"section",
93
+ # :text=>{:type=>"mrkdwn", :text=>"Your <https://google.com|build> is ready."}
94
+ # }]
95
+ ```
96
+
97
+ While the API squishes whitespace (much in the same way HTML does), it may
98
+ sometimes be useful to add a blank line between text _without_ adding a new
99
+ section to your message. To do so, use the pseudo-element `blank_line`.
100
+
101
+ ```ruby
102
+ SlackMessage.build do
103
+ text "don't let this line"
104
+ blank_line
105
+ text "touch this line."
106
+ end
107
+
108
+ # => => [{:type=>"section",
109
+ # :text=>{:type=>"mrkdwn", :text=>"don't let this line\nā€ƒ\ntouch this line."}
110
+ # }]
111
+ ```
112
+
113
+ Note that between the two newlines in the above example is a unicode emspace,
114
+ which the API will respect as a line worth rendering.
115
+
116
+ ### Explicitly Declared Sections
117
+
118
+ Adding more sections is trivial. Simply declare each section and it will be
119
+ separated in the rendered message. This can often occur when looping.
120
+
121
+ ```ruby
122
+ SlackMessage.build do
123
+ pet_types.each do |type, breeds|
124
+ section do
125
+ text "*#{type}:* #{breeds.join(", ")}"
126
+ end
127
+ end
128
+ end
129
+ ```
130
+
131
+ It can also be useful to add a visual divider (similar to an `hr` in HTML)
132
+ between sections. To add one of these, use the `divider` helper. You can also
133
+ add a divider at the end of all the sections, but it often looks silly.
134
+
135
+ ```ruby
136
+ SlackMessage.build do
137
+ section do
138
+ text "*Topsiders:* Emily, Elsie, Derick"
139
+ end
140
+
141
+ divider
142
+
143
+ section do
144
+ text "*Undergrounders:* Kristina, Lauren, Different Emily"
145
+ end
146
+ end
147
+
148
+ # => [
149
+ # {:type=>"section", :text=>{:type=>"mrkdwn", :text=>"*Topsiders:* Emily, Elsie, Derick"}},
150
+ # {:type=>"divider"},
151
+ # {:type=>"section", :text=>{:type=>"mrkdwn", :text=>"*Undergrounders:* Kristina, Lauren, Different Emily"}}
152
+ # ]
153
+ ```
154
+
155
+ Note that a divider can only occur between sections, not within a single
156
+ section. Because of how implicit sections are built, it may look like this
157
+ works for simple messages. But, you may have troubles when you start adding
158
+ more complicated elements to your messages.
159
+
160
+ ### Buttons
161
+
162
+ BlockKit allows you to specify a button to the right of a section / block. That
163
+ button will be aligned outside the normal space for a section, and is meant to
164
+ link out of the app. To create one of these, use the `link_button` helper.
165
+
166
+ ```ruby
167
+ SlackMessage.build do
168
+ text "Your daily stats are ready @here"
169
+ link_button "Stats Dashboard", stats_dashboard_url
170
+ end
171
+
172
+ # => [{:type=>"section",
173
+ # :text=>{:type=>"mrkdwn", :text=>"Your daily stats are ready @here"},
174
+ # :accessory=>
175
+ # {:type=>"button",
176
+ # :url=>"http://yoursite.com/stats_dashboard",
177
+ # :text=>{:type=>"plain_text", :text=>"Stats Dashboard", :emoji=>true},
178
+ # :style=>:primary}}]
179
+ ```
180
+
181
+ Slack allows three styles for buttons: `default`, `primary`, and `danger`.
182
+ These correspond to gray, green and red buttons respectively. If not specified,
183
+ SlackMessage will use the `primary` style for buttons. I get that this could be
184
+ confusing when there is a style specifically named default, but in my
185
+ experience, a colorful button is way more common.
186
+
187
+ You can override button style by specifying the style with your link button.
188
+
189
+ ```ruby
190
+ SlackMessage.build do
191
+ text "A job has failed catastrophically!"
192
+ link_button "Sidekiq Dashboard", sidekiq_dashboard_url, style: :danger
193
+ end
194
+
195
+ # => [{:type=>"section",
196
+ # :text=>{:type=>"mrkdwn", :text=>"A job has failed catastrophically!"},
197
+ # :accessory=>
198
+ # {:type=>"button",
199
+ # :url=>"https://yoursite.com/sidekiq",
200
+ # :text=>{:type=>"plain_text", :text=>"Sidekiq Dashboard", :emoji=>true},
201
+ # :style=>:danger}}]
202
+ ```
203
+
204
+ ### Ordered and Unordered Lists
205
+
206
+ The Slack API doesn't have native support for HTML-style ordered and unordered
207
+ lists, but there are convenience methods in SlackMessage to render a close
208
+ approximation.
209
+
210
+ ```ruby
211
+ SlackMessage.build do
212
+ section do
213
+ text '*Pet Goodness Tiers*'
214
+
215
+ ol([
216
+ 'tiny pigs',
217
+ 'reptiles',
218
+ 'dogs',
219
+ 'cats',
220
+ ])
221
+ end
222
+
223
+ section do
224
+ text '_voted by_'
225
+ ul(['Joe', 'Emily', 'Sophia', 'Matt'])
226
+ end
227
+ end
228
+ ```
229
+
230
+ Because Slack automatically collapses leading whitespace, indention of lists is
231
+ handled using unicode emspaces. Bullets for unordered lists are also unicode
232
+ characters to avoid being read as markdown.
233
+
234
+ ### List Items (e.g. HTML dt & dd)
235
+
236
+ When trying to represent title / value lists, you can use the "list item" block
237
+ type to pass a set of values. Slack does not allow you to customize how many
238
+ items are shown per line, so you'll just have to work with it.
239
+
240
+ ```ruby
241
+ SlackMessage.build do
242
+ text 'Import results are available!'
243
+
244
+ list_item 'Import Date', Date.today.to_s
245
+ list_item 'Items Imported', 55_000
246
+ list_item 'Errors', 23
247
+ list_item 'Bad Values', errors.map(&:to_s)
248
+ end
249
+ ```
250
+
251
+ ### Images and Accessory Images
252
+
253
+ There are two main types of images in Slack: the
254
+ [image](https://imgur.com/XEUap1r) and the [accessory
255
+ image](https://imgur.com/zuhjBDq). In short, `accessory_image` is part of a
256
+ section itself and is shown alongside an existing block, while `image` is shown
257
+ as its own top-level element.
258
+
259
+ Accordingly, an accessory image should be used within a section. An accessory
260
+ image can accept alt-text, which is also a best practice, for usability
261
+ reasons.
262
+
263
+ ```ruby
264
+ SlackMessage.build do
265
+ section do
266
+ text 'Looks like the coffee machine is empty.'
267
+ accessory_image 'https://your.com/empty_coffee_logo.jpg', alt_text: 'logo of a forlorn coffee cup'
268
+ end
269
+ end
270
+ ```
271
+
272
+ Only one accessory image can be used per section, and declaring more will issue
273
+ a warning and simply override the previous accessory image.
274
+
275
+ By contrast, `image` can be used many times, and will create a new top-level
276
+ section for each call. Image accepts alt-text, but also a title, which will
277
+ be displayed above the image (along with an icon to collapse the image).
278
+
279
+ ```ruby
280
+ SlackMessage.build do
281
+ section do
282
+ text 'Most Recent Tiny Pig Images'
283
+ end
284
+
285
+ image 'https://your.com/employee_pets/best/pig_1.jpg', alt_text: 'a tiny pig eating ice cream', title: 'Spider Pig'
286
+ image 'https://your.com/employee_pets/best/pig_2.jpg', alt_text: 'a tiny pig smiling mischeviously', title: 'Porkeypine'
287
+ image 'https://your.com/employee_pets/best/pig_3.jpg', alt_text: 'a tiny pig with wellies and an umbrella', title: 'Albert Sweinstein'
288
+ end
289
+ ```
290
+
291
+ Sectionless messages can also use `accessory_image`, but this can get confusing
292
+ since they could potentially be interspersed with top-level images, so I
293
+ wouldn't recommend it.
294
+
295
+ ```ruby
296
+ # the difference between these two image styles is confusing, and the call
297
+ # to `image` closed the current section and started a new one.
298
+ SlackMessage.build do
299
+ text 'Looks like the coffee machine is empty.'
300
+ accessory_image 'https://your.com/empty_coffee_logo.jpg'
301
+
302
+ text '*Most Recent Coffee Maker Surveillance Photo*'
303
+ image 'https://your.com/surveillance/coffee/current.jpg'
304
+ end
305
+ ```
306
+
307
+ ### Footers (Context)
308
+
309
+ Slack allows you to add a small additional piece of text to your message, which
310
+ will be rendered in italics and small text. It can support both links and
311
+ emoji, and is useful for providing minor details for your message.
312
+
313
+ ```ruby
314
+ SlackMessage.build do
315
+ text "New coffee complaints have been added."
316
+ context "this complaint added by #{link('Joe Mastey', 'hello@joemastey.com')}."
317
+ end
318
+
319
+ # => [{:type=>"section",
320
+ # :text=>{:type=>"mrkdwn", :text=>"New coffee complaints have been added."}
321
+ # },
322
+ # {:type=>"context", :elements=>
323
+ # [{:type=>"mrkdwn",
324
+ # :text=>"this complaint added by <hello@joemastey.com|Joe Mastey>."
325
+ # }]
326
+ # }]
327
+ ```
328
+
329
+ Context does not belong to a section, and only one can be added to your entire
330
+ slack message. Specifying another `context` will issue a warning and overwrite
331
+ any previous call.
332
+
333
+ ### Bot Customization
334
+
335
+ By default - and with scheduled messages - Slack will use the name and icon of
336
+ the Slack app whose API key you configured. As seen before, it's possible to
337
+ override those default names and icons in configuration. However, it can also
338
+ be customized per-message.
339
+
340
+ ```ruby
341
+ SlackMessage.build do
342
+ bot_icon ":sad_robot:"
343
+ bot_name "BadNewsBuildBot"
344
+
345
+ text "The build is broken. @here"
346
+ end
347
+
348
+ # => [{:type=>"section", :text=>{:type=>"mrkdwn", :text=>"The build is broken. @here"}}]
349
+ ```
350
+
351
+ Notice that the bot details aren't shown in the output of the `build` command.
352
+ To view the change to the message payload from these calls, use `debug` mode.
353
+
354
+ The `bot_icon` can be specified as either an emoji (`:shipit:`), or a URL
355
+ pointing to an image (`http://mysite.com/shipit.png`). Any other value seems to
356
+ cause an error.
357
+
358
+ ### Custom Notification Text
359
+
360
+ For users who have notifications turned on, Slack will provide a small message
361
+ preview when you send them a message. By default, this preview will take the
362
+ first several words from your message.
363
+
364
+ However, you can specify some custom notification text to be shown to the user.
365
+ This text supports basic emoji and formatting, but nothing complicated.
366
+
367
+ ```ruby
368
+ SlackMessage.build do
369
+ notification_text "Having issues with the build. :ohnoes:"
370
+
371
+ text "The build is broken. The error message was 'undefined method round for NilClass'"
372
+
373
+ # => [{:type=>"section",
374
+ # :text=>
375
+ # {:type=>"mrkdwn",
376
+ # :text=>"The build is broken. The error message was 'undefined method round for NilClass'"}}]
377
+ end
378
+ ```
379
+
380
+ Again notice that notification text is not set within the blocks themselves, so
381
+ you will need to enable debugging to see how it changes what is sent to the
382
+ API. Only one custom notification is allowed, so further calls will issue a
383
+ warning and replace the previous notification text.
384
+
385
+ ---
386
+
387
+ Next: [Editing Messages](https://jmmastey.github.io/slack_message/04_editing_messages)
@@ -0,0 +1,87 @@
1
+ ## Updating a Previous Message
2
+
3
+ After you've posted a message, you may want to edit it later. Interactive bots,
4
+ for instance, may want to repeatedly update a message.
5
+
6
+ Posting will always return an object representing your posted message.
7
+
8
+ ```ruby
9
+ message = SlackMessage.post_to('#general') do
10
+ text "Getting ready..."
11
+ end
12
+ ```
13
+
14
+ Then, you can use that response object to go back and rewrite the message a
15
+ little or a lot.
16
+
17
+ ```ruby
18
+ SlackMessage.update(message) do
19
+ text "Done!"
20
+ end
21
+ ```
22
+
23
+ The new message contents will be built and updated via the API. To give an
24
+ example, you could alert slack to a job status by updating your original
25
+ message.
26
+
27
+
28
+ ```ruby
29
+ class SomeWorker < ApplicationWorker
30
+ def perform
31
+ post_started_status
32
+
33
+ # ... perform work here
34
+
35
+ post_finished_status
36
+ end
37
+
38
+ private
39
+
40
+ def post_started_status
41
+ @message = SlackMessage.post_as(:job_worker) do
42
+ text "Beginning upload."
43
+ end
44
+ end
45
+
46
+ def post_finished_status
47
+ SlackMessage.update(@message) do
48
+ text "Finished upload! @here come and get it."
49
+ link_button "See Results", uploaded_data_url
50
+ end
51
+ end
52
+ end
53
+ ```
54
+
55
+ ### Storing Response Objects for Later
56
+
57
+ Since updates are likely to occur long after you post the original message, you
58
+ may want to persist a reference to the message until you need to update it
59
+ later. As one option, you could serialize the response object for later.
60
+
61
+ ```ruby
62
+ # initially
63
+ message = SlackMessage.post_to('#general') do
64
+ text "Starting..."
65
+ end
66
+ redis_connection.set(self.message_cache_key, Marshal.dump(message))
67
+
68
+
69
+ # later
70
+ message = Marshal.load(redis_connection.get(self.message_cache_key))
71
+ SlackMessage.update(message) do
72
+ text "Finished!"
73
+ end
74
+ ```
75
+
76
+ ### Updating Scheduled Messages
77
+
78
+ Sadly, there's currently no way to edit a scheduled message. You'll receive an
79
+ error if you attempt to call `update` on a scheduled message.
80
+
81
+ See the [API documentation for
82
+ chat.update](https://api.slack.com/methods/chat.update) for more information on
83
+ updating messages.
84
+
85
+ ---
86
+
87
+ Next: [Deleting Messages](https://jmmastey.github.io/slack_message/05_deleting_messages)
@@ -0,0 +1,45 @@
1
+ ## Deleting Messages
2
+
3
+ Deleting a message is much like editing a message, only simpler. Just like when
4
+ you edit a message, you'll need a reference to the message you posted.
5
+
6
+ ```ruby
7
+ message = SlackMessage.post_to('#general') do
8
+ text "Testing: #{SLACK_SECRET_KEY}"
9
+ end
10
+ ```
11
+
12
+ Then you can simply call the `delete` method to make up for your mistakes.
13
+
14
+ ```ruby
15
+ SlackMessage.delete(message)
16
+ ```
17
+
18
+ *Important Note: It's not possible to delete a message sent directly to a user.
19
+ It's also not possible to delete a scheduled message once it's already posted.
20
+ Don't send anything you don't want your boss to read.*
21
+
22
+ As with editing a message, it's possible to persist messages to redis / your
23
+ database to be removed at a later date.
24
+
25
+ ```ruby
26
+ # initially
27
+ message = SlackMessage.post_to('#general') do
28
+ text "Testing: #{SLACK_SECRET_KEY}"
29
+ end
30
+ redis_connection.set(self.message_cache_key, Marshal.dump(message))
31
+
32
+
33
+ # later
34
+ message = Marshal.load(redis_connection.get(self.message_cache_key))
35
+ SlackMessage.delete(message)
36
+ ```
37
+
38
+ See the [API documentation for
39
+ chat.delete](https://api.slack.com/methods/chat.delete) or
40
+ [chat.deleteScheduledMessage](https://api.slack.com/methods/chat.deleteScheduledMessage)
41
+ for more information on deleting messages.
42
+
43
+ ---
44
+
45
+ Next: [Mentions / Notifying Users](https://jmmastey.github.io/slack_message/06_notifying_users)
@@ -0,0 +1,62 @@
1
+ ## Mentions / Notifying Users
2
+
3
+ There are several supported ways to tag and notify users. As mentioned
4
+ initially, it's possible to DM a user by their account email.
5
+
6
+ ```ruby
7
+ SlackMessage.post_to('hello@joemastey.com') do
8
+ text "Hi there!"
9
+ end
10
+ ```
11
+
12
+ You can also mention a user by email within a channel by wrapping their name in
13
+ tags.
14
+
15
+ ```ruby
16
+ SlackMessage.post_to('#general') do
17
+ bot_name "CoffeeBot"
18
+ bot_icon ":coffee:"
19
+
20
+ text ":coffee: It's your turn to make coffee <hello@joemastey.com>."
21
+ end
22
+ ```
23
+
24
+ Emails that are not wrapped in tags will be rendered as normal email addresses.
25
+ Additionally, Slack will automatically convert a number of channel names and
26
+ tags you're probably already used to.
27
+
28
+ ```ruby
29
+ SlackMessage.post_to('#general') do
30
+ bot_name "CoffeeBot"
31
+ bot_icon ":coffee:"
32
+
33
+ text "@here There's no coffee left! Let #general know when you fix it."
34
+ end
35
+ ```
36
+
37
+ By default, the desktop notification for a message will be the text of the
38
+ message itself. However, you can customize desktop notifications if you prefer.
39
+
40
+ ```ruby
41
+ SlackMessage.post_to('hello@joemastey.com') do
42
+ bot_name "CoffeeBot"
43
+ bot_icon ":coffee:"
44
+
45
+ notification_text "It's a coffee emergency!"
46
+ text "There's no coffee left!"
47
+ end
48
+ ```
49
+
50
+ ### Using @channel or @here
51
+
52
+ Not really a feature, but Slack will respect usage of `@here` and `@channel`.
53
+
54
+ ```ruby
55
+ SlackMessage.post_to('#general') do
56
+ text "Hey @channel, don't forget to submit your drink requests."
57
+ end
58
+ ```
59
+
60
+ ---
61
+
62
+ Next: [Testing](https://jmmastey.github.io/slack_message/07_testing)
@@ -0,0 +1,49 @@
1
+ ## Testing
2
+
3
+ You can do some basic testing against SlackMessage, at least if you use RSpec!
4
+ You'll need to require and include the testing behavior in your spec_helper
5
+ file.
6
+
7
+ ```ruby
8
+ require 'slack_message/rspec'
9
+
10
+ RSpec.configure do |config|
11
+ include SlackMessage::RSpec
12
+
13
+ # your other spec_helper config
14
+ end
15
+ ```
16
+
17
+ This will prevent API calls from leaking in your tests, and will allow you
18
+ access to some custom matchers.
19
+
20
+ ```ruby
21
+ expect {
22
+ SlackMessage.post_to('#general') { text "foo" }
23
+ }.to post_slack_message_to('#general').with_content_matching(/foo/)
24
+
25
+ expect {
26
+ SlackMessage.post_as(:schmoebot) { text "foo" }
27
+ }.to post_slack_message_as(:schmoebot)
28
+
29
+ expect {
30
+ SlackMessage.post_as(:schmoebot) { text "foo" }
31
+ }.to post_slack_message_as('Schmoe Bot')
32
+
33
+ expect {
34
+ SlackMessage.post_as(:schmoebot) { text "foo" }
35
+ }.to post_slack_message_with_icon(':schmoebot:')
36
+
37
+ expect {
38
+ SlackMessage.post_as(:schmoebot) { text "foo" }
39
+ }.to post_slack_message_with_icon_matching(/gravatar/)
40
+
41
+ expect {
42
+ SlackMessage.post_to('#general') { text "foo" }
43
+ }.to post_to_slack
44
+ ```
45
+
46
+ Be forewarned, I'm frankly not that great at more complicated RSpec matchers,
47
+ so I'm guessing there are some bugs. Also, because the content of a message
48
+ gets turned into a complex JSON object, matching against content isn't capable
49
+ of very complicated regexes.
data/docs/_config.yml ADDED
@@ -0,0 +1,6 @@
1
+ plugins:
2
+ - jekyll-relative-links
3
+ relative_links:
4
+ enabled: true
5
+ collections: true
6
+ theme: jekyll-theme-midnight
data/docs/index.md ADDED
@@ -0,0 +1,53 @@
1
+ * [Getting Started / Configuration](https://jmmastey.github.io/slack_message/01_configuration)
2
+ * [Posting a Message](https://jmmastey.github.io/slack_message/02_posting_a_message)
3
+ * [The SlackMessage DSL](https://jmmastey.github.io/slack_message/03_message_dsl)
4
+ * [Editing Messages](https://jmmastey.github.io/slack_message/04_editing_messages)
5
+ * [Deleting Messages](https://jmmastey.github.io/slack_message/05_deleting_messages)
6
+ * [Mentions / Notifying Users](https://jmmastey.github.io/slack_message/06_notifying_users)
7
+ * [Testing](https://jmmastey.github.io/slack_message/07_testing)
8
+
9
+ SlackMessage is a gem that makes it easy to send messages to Slack from your
10
+ application. _Really_ easy.
11
+
12
+ ```ruby
13
+ SlackMessage.post_to('#general') do
14
+ text "We did it @here! :thumbsup:"
15
+ end
16
+ ```
17
+
18
+ And not just simple messages. You can compose complicated messages quickly in a
19
+ DSL that's focused on usability and maintainability. It can be tough to
20
+ maintain code in other similar gems, but not here.
21
+
22
+ ```ruby
23
+ SlackMessage.post_to('hello@joemastey.com') do
24
+ section do
25
+ text "A job has generated some output for you to review."
26
+ text 'And More' * 10
27
+ link_button "See Results", "https://google.com"
28
+ end
29
+
30
+ section do
31
+ text ":unlock-new: New Data Summary"
32
+
33
+ list_item "Date", "09/05/2021"
34
+ list_item "Total Imported", 45_004
35
+ list_item "Total Errors", 5
36
+ end
37
+
38
+ divider
39
+
40
+ section do
41
+ text "See more here: #{link('result', 'https://google.com')}"
42
+ end
43
+
44
+ context "Kicked off by <hello@joemastey.com> at **9:05am**"
45
+ end
46
+ ```
47
+
48
+ It has no dependencies and minimal configuration needs, so you can get up and
49
+ running quickly.
50
+
51
+ ---
52
+
53
+ Next: [Get Started](https://jmmastey.github.io/slack_message/01_configuration)