Back to script library
Entra / Microsoft 365 · Exchange Online

Send welcome email graph

Sends welcome mail to newly created mailboxes using Microsoft Graph mail send with an app registration.

Connect & set up

Run these once per session. All scopes are read-only unless the script makes changes.

Connect-ExchangeOnline

Run it

The main script. Copy it, or download the .ps1 and run it from your console.

param(
[string] $TenantId = "",
[string] $AppId = "",
[int] $LookbackDays = 7
)
$Modules = Get-Module
If ("ExchangeOnlineManagement" -notin $Modules.Name) {Write-Host "Please connect to Exchange Online Management before continuing...";break}
# Date to Check for new accounts - we use the last 7 days here, but that's easily changable.
[string]$CheckDate = (Get-Date).AddDays(-$LookbackDays)
# Get Graph access token - change these values for the app you use.
$AppSecret = "~_Q2.IPI3kpbmhOG.VtCb1r0_J9G4-D8jG"
# Construct URI and body needed for authentication
$uri = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"
$body = @{
client_id = $AppId
scope = "https://graph.microsoft.com/.default"
client_secret = $AppSecret
grant_type = "client_credentials"
}
$tokenRequest = Invoke-WebRequest -Method Post -Uri $uri -ContentType "application/x-www-form-urlencoded" -Body $body -UseBasicParsing
# Unpack Access Token
$token = ($tokenRequest.Content | ConvertFrom-Json).access_token
$Headers = @{
'Content-Type' = "application\json"
'Authorization' = "Bearer $Token" }
# Define some variables for the message
#HTML header with styles
$htmlhead="<html>
<style>
BODY{font-family: Arial; font-size: 10pt;}
H1{font-size: 22px;}
H2{font-size: 18px; padding-top: 10px;}
H3{font-size: 16px; padding-top: 8px;}
</style>"
#Header for the message
$HtmlBody = "<body>
<h1>Welcome to Our Company</h1>
<p><strong>Generated:</strong> $(Get-Date -Format g)</p>
<h2><u>We're Pleased to Have You Here</u></h2>"
# Other lines
$htmlline1 = "<p><b>Welcome to Office 365</b></p>"
$htmlline2 = "<p>You can open Office Online by clicking <a href=https://www.office.com/?auth=2>here</a> </p>"
$htmlline3 = "<p>Have a great time and be sure to call the help desk if you need assistance.</p>"
# Find all mailboxes created in the target period
[datetime]$DisplayDate = $CheckDate
Write-Host ("Finding User mailboxes created since {0}" -f (Get-Date($DisplayDate) -format g))
$Users = (Get-ExoMailbox -Filter "WhenMailboxCreated -gt '$CheckDate'" -RecipientTypeDetails UserMailbox -ResultSize Unlimited -Properties WhenMailboxCreated | Select-Object WhenMailboxCreated, DisplayName, UserPrincipalName, PrimarySmtpAddress)
If (!($Users)) {Write-Host "No users found - exiting" ; break} Else { Write-Host $Users.Count "mailboxes found to process"}
# Mail.Send can send from any user. In this example, because we're sending messages to welcome people, we look up the mailboxes on the system to
# find one tagged as the HR admin. You can use whatever method you like as long as the result is a resolveable SMTP address. If you use an application
# access policy to restrict access to the API, make sure this user is included.
$MsgFrom = Get-Recipient -Filter {CustomAttribute1 -eq "HRAdmin"} | Select-Object -ExpandProperty PrimarySmtpAddress
If ($null -eq $MsgFrom) { Write-Host "Can't find user defined as the sender for the messages - exiting!"; break}
# Use the same approach to define CC recipients for the message
$ccRecipient1 = Get-Recipient -Filter {CustomAttribute1 -eq "HRCC1"} | Select-Object -ExpandProperty PrimarySmtpAddress
$ccRecipient2 = Get-Recipient -Filter {CustomAttribute1 -eq "HRCC2"} | Select-Object -ExpandProperty PrimarySmtpAddress
If (($null -eq $ccRecipient1 ) -or ($null -eq $ccRecipient2)) { Write-Host "CC Recipients are not defined. Exiting!" ; break}
Write-Host "Messages will be sent from" $MsgFrom "and CC'd to" $ccRecipient1 "and" $ccRecipient2
# Define attachment to send to new users
$AttachmentFile = "C:\temp\WelcomeToOffice365ITPros.docx"
$ContentBase64 = [convert]::ToBase64String( [system.io.file]::readallbytes($AttachmentFile))
$SentMessages = 0
# Create and send welcome message for each user
ForEach ($User in $Users) {
$EmailRecipient = $User.PrimarySmtpAddress
Write-Host "Sending welcome email to" $User.DisplayName
$MsgSubject = "A Hundred Thousand Welcomes to " + $User.DisplayName
$htmlHeaderUser = "<h2>New User " + $User.DisplayName + "</h2>"
$htmlline1 = "<p><b>Welcome to Office 365</b></p>"
$htmlline2 = "<p>You can open Office Online by clicking <a href=https://www.office.com/?auth=2>here</a> </p>"
$htmlline3 = "<p>Have a great time and be sure to call the help desk if you need assistance.</p>"
$htmlbody = $htmlheaderUser + $htmlline1 + $htmlline2 + $htmlline3 + "<p>"
$HtmlMsg = "</body></html>" + $HtmlHead + $HtmlBody
# Create message body and properties and send
$MessageParams = @{
"URI" = "https://graph.microsoft.com/v1.0/users/$MsgFrom/sendMail"
"Headers" = $Headers
"Method" = "POST"
"ContentType" = 'application/json'
"Body" = (@{
"message" = @{
"subject" = $MsgSubject
"body" = @{
"contentType" = 'HTML'
"content" = $htmlMsg }
"attachments" = @(
@{
"@odata.type" = "#microsoft.graph.fileAttachment"
"name" = $AttachmentFile
"contenttype" = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
"contentBytes" = $ContentBase64 } )
"toRecipients" = @(
@{
"emailAddress" = @{"address" = $EmailRecipient }
} )
"ccRecipients" = @(
@{
"emailAddress" = @{"address" = $ccRecipient1 }
} ,
@{
"emailAddress" = @{"address" = $ccRecipient2 }
} )
}
}) | ConvertTo-JSON -Depth 6
}
# Send the message
Invoke-RestMethod @Messageparams
$SentMessages++
}
Write-Host "All done." $SentMessages "welcome messages sent to happy users"

Parameters

ParameterDefaultNotes
-TenantId""Microsoft Entra tenant ID for app-only Graph authentication.
-AppId""Application (client) ID for the app registration used to connect.
-LookbackDays7How many days back to search for newly created mailboxes or recent activity.
Attribution