-
Notifications
You must be signed in to change notification settings - Fork 76
/
Get-EmailsNotSentUsingTLS.ps1
225 lines (187 loc) · 12.1 KB
/
Get-EmailsNotSentUsingTLS.ps1
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
<#
.DESCRIPTION
When forcing TLS encryption on outgoing e-mails due to GDPR requirements, Exchange Online will try sending the e-mail for 24 hours before dropping it and returning a default NDR (non-delivery report).
Waiting 24 hours to get informed if your e-mail was delivered or not is not ideal, thus this script was created.
The script will run on a schedule (say every 15 minutes) and look for e-mails send and recieved in the past 16 minutes.
If any of the e-mails in those past 16 minutes are delayed due to lack of TLS support with the recipient, the script will send a custom e-mail to the sender right away.
.NOTES
Filename: Get-EmailsNotSentUsingTLS.ps1
Version: 1.0
Author: Martin Bengtsson
Blog: www.imab.dk
Twitter: @mwbengtsson
Version history:
1.0 - Script created
.LINK
#>
# Azure automation credentials
# EDIT these to match your own credentials
$AzureCredentials = Get-AutomationPSCredential -Name "AzureAutomation"
$hlpCredentials = Get-AutomationPSCredential -Name "hlp"
# Connect to the Exchange Online Management module (this is available in the module gallery in Azure Automation)
if (Get-Module -Name ExchangeOnlineManagement -ListAvailable) {
try {
Write-Verbose -Verbose -Message "Connecting to Exchange Online using $AzureCredentials"
Connect-ExchangeOnline -Credential $AzureCredentials -ShowProgress $true
Write-Verbose -Verbose -Message "Successfully connected to Exchange Online"
}
catch {
Write-Verbose -Verbose -Message "Failed to connect to Exchange Online. Please check if credentials and permissions are correct. Breaking script"
break
}
}
elseif (-NOT(Get-Module -Name ExchangeOnlineManagement -ListAvailable)) {
Write-Verbose -Verbose -Message "The Exchange Online module is not available. Breaking script"
break
}
# Office 365 and other variables
# EDIT this to suit your needs
$emailSmtp = "smtp.office365.com"
$emailPort = "587"
$emailFrom = "[email protected]"
$emailSubject = "E-mail sent without encryption!"
$emailBcc = "[email protected]", "[email protected]"
$url = "https://imab.dk"
$automaticReply = "Automatic reply:*"
$sendingDomain = "*@imab.dk"
# Reasons reported when e-mails are pending due to lack of TLS support
# These are the reasons report I have found. Maybe there is more? If so, they can easily be added
$reason0 = "Cannot connect to remote server"
$reason1 = "STARTTLS is required to send mail"
$reason2 = "Security status InvalidToken"
# Format date and time
# This is where we configure how far back the script will look for e-mails, which is currently 16 minutes
$localCulture = Get-Culture
$regionDateFormat = [System.Globalization.CultureInfo]::GetCultureInfo($LocalCulture.LCID).DateTimeFormat.LongDateTimePattern
$dateEnd = Get-Date -f $RegionDateFormat
$dateStart = $dateEnd.AddMinutes(-16)
# Get all emails from the last 16 minutes which are pending and not an automatic reply
# Automatic replies are filtered out. We don't want to trigger an e-mail based on an out of office reply
$emailsPending = @()
$emailsPending = Get-MessageTrace -StartDate $dateStart.ToUniversalTime() -EndDate $dateEnd.ToUniversalTime() | Where-Object {$_.Status -eq "Pending" -AND $_.Subject -notlike $automaticReply} | Select-Object Received,SenderAddress,RecipientAddress,MessageTraceID,Subject
# Loop through each e-mail found
Write-Verbose -Verbose -Message "Looping through each e-mail message with a status of pending in the Exchange Online queue"
foreach ($email in $emailsPending) {
$timestamp = $email.Received
$sender = $email.SenderAddress
$recipient = $email.RecipientAddress
$messageId = $email.MessageTraceId
$subject = $email.Subject
# Get further message details from each e-mail
# This is needed to see the exact cause of why the email is pending
try {
$result = Get-MessageTraceDetail -SenderAddress $sender -RecipientAddress $recipient -MessageTraceId $messageid
}
catch { }
# Loop through each event on each e-mail
foreach ($event in $result.Event) {
# Only grab e-mails which have a status equal to Defer. This indicates e-mails being delayed for various reasons
if ($event -eq "Defer") {
# Loop through each line of details
foreach ($detail in $result.Detail) {
# Sorting out empty lines of details
if ($detail -ne $null) {
# Sorting again, only grabbing e-mails which matches the reasons for being delayed due to lack of TLS support with the recipient
if (($detail -match $reason1) -AND ($detail -match $reason0)) {
# E-mail being sent internally in the sending domain is not interesting. Only grabbing e-mails going out externally
if (($sender -like $sendingDomain) -AND ($recipient -notlike $sendingDomain)) {
Write-Verbose -Verbose -Message "*** E-mail found which matches all the criteria ***"
Write-Verbose -Verbose -Message "Sender is: $sender recipient is: $recipient subject is: $subject MessageID is: $messageId"
# Creating e-mail body including stylesheet
$emailBody = "
<html>
<head>
<style type='text/css'>
h1 {
color: #002933;
font-family: verdana;
font-size: 20px;
}
h2 {
color: #002933;
font-family: verdana;
font-size: 15px;
}
body {
color: #002933;
font-family: verdana;
font-size: 13px;
}
</style>
</head>
<body>
<h1>Attention: Your e-mail has NOT been delivered!</h1>
<p>Your e-mail sent to $recipient, sent on $timestamp (UTC+0), with the subject: '$subject', has not been delivered.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce at ultricies erat. Duis ac aliquet massa. Vestibulum bibendum at velit vel volutpat.<br>
Donec vel orci tristique, pulvinar felis nec, finibus quam. Phasellus pulvinar leo est, et efficitur eros sollicitudin non. Nunc congue porta eleifend.<br>
Pellentesque aliquet sagittis egestas. Nam eget efficitur mauris. Maecenas at commodo nisi. Pellentesque fermentum neque posuere convallis congue.<br>
Curabitur eu diam risus. Proin ipsum eros, pellentesque nec tempus non, feugiat consectetur tortor.</p>
<p>Best regards,<br><a href=$url>www.imab.dk</a></p>
</body>
</html>
"
# Try sending the e-mail using the SMTP details provided
try {
Write-Verbose -Verbose -Message "Sending a custom bounce e-mail to $sender, notifying him/her about the lack of encryption support with the recipient at $recipient"
Send-MailMessage -To $sender -From $emailFrom -Subject $emailSubject -Body $emailBody -Credential $hlpCredentials -SmtpServer $emailSmtp -Port $emailPort -Priority High -Encoding Unicode -UseSsl -BodyAsHtml
}
catch {
Write-Verbose -Verbose -Message "Failed to send the e-mail to $sender"
}
}
}
# Looking for a third reason to the email being delayed (reason2)
elseif (($detail -match $reason0) -AND ($detail -match $reason2)) {
# E-mail being sent internally in the sending domain is not interesting. Only grabbing e-mails going out externally
if (($sender -like $sendingDomain) -AND ($recipient -notlike $sendingDomain)) {
Write-Verbose -Verbose -Message "*** E-mail found which matches all the criteria ***"
Write-Verbose -Verbose -Message "Sender is: $sender recipient is: $recipient subject is: $subject MessageID is: $messageId"
# Creating e-mail body including stylesheet
$emailBody = "
<html>
<head>
<style type='text/css'>
h1 {
color: #002933;
font-family: verdana;
font-size: 20px;
}
h2 {
color: #002933;
font-family: verdana;
font-size: 15px;
}
body {
color: #002933;
font-family: verdana;
font-size: 13px;
}
</style>
</head>
<body>
<h1>Attention: Your e-mail has NOT been delivered!</h1>
<p>Your e-mail sent to $recipient, sent on $timestamp (UTC+0), with the subject: '$subject', has not been delivered.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce at ultricies erat. Duis ac aliquet massa. Vestibulum bibendum at velit vel volutpat.<br>
Donec vel orci tristique, pulvinar felis nec, finibus quam. Phasellus pulvinar leo est, et efficitur eros sollicitudin non. Nunc congue porta eleifend.<br>
Pellentesque aliquet sagittis egestas. Nam eget efficitur mauris. Maecenas at commodo nisi. Pellentesque fermentum neque posuere convallis congue.<br>
Curabitur eu diam risus. Proin ipsum eros, pellentesque nec tempus non, feugiat consectetur tortor.</p>
<p>Best regards,<br><a href=$url>www.imab.dk</a></p>
</body>
</html>
"
# Try sending the e-mail using the SMTP details provided
try {
Write-Verbose -Verbose -Message "Sending a custom bounce e-mail to $sender, notifying him/her about the lack of encryption support with the recipient at $recipient"
Send-MailMessage -To $sender -From $emailFrom -Subject $emailSubject -Body $emailBody -Credential $hlpCredentials -SmtpServer $emailSmtp -Port $emailPort -Priority High -Encoding Unicode -UseSsl -BodyAsHtml
}
catch {
Write-Verbose -Verbose -Message "Failed to send the e-mail to $sender"
}
}
}
}
}
}
}
}
Write-Verbose -Verbose -Message "Script has completed"