How to send unique individual emails?

I need to send one unique email to different email addresses exporting them from a .csv file. I have a code but it just sends the message to all of the emails in one email.

#Import the file that store username and emails
$data = import-csv "C:.csv"

#Declare email content
$email = $data.Email | select -unique

ForEach ($email in $data)
{
$From = "***@gmail.com"
$To = $data.Email
$Subject = "Test"
$Body = "Test"
$SMTPServer = "smtp.gmail.com"
$SMTPPort = "587"
}

#Sending email
Send-MailMessage -From $From -to $To -Subject $Subject `
-Body $Body -SmtpServer $SMTPServer -port $SMTPPort -UseSsl `
-Credential (Get-Credential -Message "Please input valid credentials")

The code above works but as mentioned it sends just one email to all the email addresses in the file. I need it to send one for each email.

Upvotes: 3

Views: 698

Answers (3)

Theo
Theo

Reputation: 61028

The main problem I see in your code is that you first create an array of unique email addresses from the csv file in a variable $email, but later on you overwrite that same value by using it in the foreach loop.

There, in every iteration, the $email variable will become a complete row from the CSV file which is obviously not what you expect it to be.

Below a slightly adjusted version of your code. Note that I also used Splatting to create a hashtable with all properties for the Send-MailMessage cmdlet, to avoid having to use the easy to overlook backtick.

#Import the file that store username and emails
$data = import-csv "D:\mail.csv"

# Get a unique array of email addresses
$addresses = $data.Email | Select-Object -Unique

# Declare Credentials
$creds = (Get-Credential -Message "Please input valid credentials")

# loop through the email addresses array and send a mail to each of them
foreach ($email in $addresses) {
    $splat = @{
        From       = "***@gmail.com"
        To         = $email
        Subject    = "Test"
        Body       = "Test"
        SmtpServer = "smtp.gmail.com"
        Port       = 587
        Credential = $creds
        UseSsl     = $true
    }

    #Sending email
    Send-MailMessage @splat
}

Note that the -Port parameter is of type Int32, so you should not quote that


Update

As requested in your comment, if you want to use more fields from the CSV file, then the code would change.
Let's assume your CSV looks anything like:

"User","Email","ManagerEmail"
"Tom","[email protected]","[email protected]"
"Dick","[email protected]","[email protected]"
"Harry","[email protected]","[email protected]"
"Dick","[email protected]","[email protected]"

(note, user Dick is duplicated)

Then the following will read the csv, deduplicate it on the Email property and send emails to each user:

# Import the file that store username and emails
# and uniquify the objectson property Email
$data = Import-Csv "D:\mail.csv" | Sort-Object -Property Email -Unique

# Declare Credentials
$creds = (Get-Credential -Message "Please input valid credentials")

# loop through the csv objects array and send a mail to each of them
foreach ($item in $data) {
    # every item is an object with properties .User, .Email and .ManagerEmail
    $splat = @{
        From       = "***@gmail.com"
        To         = $item.Email
        Cc         = $item.ManagerEmail
        Subject    = "Hi there {0}" -f $item.User
        Body       = "Test"
        SmtpServer = "smtp.gmail.com"
        Port       = 587
        Credential = $creds
        UseSsl     = $true
    }

    #Sending email
    Send-MailMessage @splat
}

Hope that helps

Upvotes: 2

Robert Dyjas
Robert Dyjas

Reputation: 5217

Most important error you made is

$To = $data.Email

where you add all the emails to To: field. Drew's suggestion is almost what you want to follow but with one remark. Your $To= assignment should use $email which represents single object from array, instead of the whole array (which is $data).

$To = $email.Email

Edit: As @Theo suggested in the comments, it's worth mentioning that the line

$email = $data.Email | select -unique

won't work as you use the same variable name later in foreach loop. What I'd suggest is to save unique email addresses to other variable

$uniqueEmails = $data.Email | select -unique

then iterate that one

# Change this
ForEach ($email in $data) {
# To this
ForEach ($email in $uniqueEmails ) {

And of course as you already saved Email propert to $uniqueEmails:

# This line
$To = $email.Email
# Should be changed to
$To = $email

Upvotes: 0

Drew
Drew

Reputation: 4020

As per comments, please find the adjusted script and reasoning.

You were looping through the CSV but only sending the email once. It looks like it would have originally sent the email to ONE person, that being the last in your CSV.

This version will loop through and send an email for each line in the CSV.

#Import the file that store username and emails
$data = import-csv "C:.csv"

#Declare email content
$email = $data.Email | select -unique

# Declare Credentials
$creds = (Get-Credential -Message "Please input valid credentials")

ForEach ($email in $data) {
    $From = "***@gmail.com"
    $To = $email.Email
    $Subject = "Test"
    $Body = "Test"
    $SMTPServer = "smtp.gmail.com"
    $SMTPPort = "587"

    #Sending email
    Send-MailMessage -From $From -to $To -Subject $Subject `
    -Body $Body -SmtpServer $SMTPServer -port $SMTPPort -UseSsl `
    -Credential $creds
}

Upvotes: 1

Related Questions