2

I want to send an e-mail using PowerShell commands in a batch file. To do this, I implemented a function called sendMail. I'm calling it like this:

setlocal enabledelayedexpansion
call:sendMail
powershell -command "!_mailCommand!"
endlocal
pause&goto:eof

And my sendMail function:

:sendMail

set "_mailCommand=&{$filenameAndPath = '!resultFile!';"
set "_mailCommand=%_mailCommand%$SMTPMessage = New-Object System.Net.Mail.MailMessage('%_mailFrom%', '%_mailTo%', '%_mailSubject%', '%_mailBody%');"
set "_mailCommand=%_mailCommand%$attachment = New-Object System.Net.Mail.Attachment($filenameAndPath);"
set "_mailCommand=%_mailCommand%$SMTPMessage.Attachments.Add($attachment);"
set "_mailCommand=%_mailCommand%$SMTPClient = New-Object Net.Mail.SmtpClient('%_mailHost%', %_mailPort%);"
set "_mailCommand=%_mailCommand%$SMTPClient.EnableSsl = $true;"
set "_mailCommand=%_mailCommand%$SMTPClient.Credentials = New-Object System.Net.NetworkCredential('%_mailFrom%','%_mailSenderPassword%');"
set "_mailCommand=%_mailCommand%$SMTPClient.Send($SMTPMessage)}"
echo %_mailSenderPassword%

Unexpectedly I get an output like this:

12345Aa!

Exception calling "Send" with "1" argument(s): "Failure sending mail."

At line:1 char:499 ... m','12345Aa^');$SMTPClient.Send($SMTPMessage)}

CategoryInfo : NotSpecified: (:) [], MethodInvocationException

FullyQualifiedErrorId : SmtpException

As you can guess, my password is 12345Aa! and I defined it at the beginning of my code as set "_mailSenderPassword=12345Aa^^!"

So what am I missing? Thanks in advance!

ozcanovunc
  • 703
  • 1
  • 8
  • 29
  • Use `set "_mailSenderPassword=12345Aa^!"` instead – jeb Jul 09 '15 at 14:48
  • 1
    Why do't you use a builtin `Send-MailMessage` cmdlet? – Vesper Jul 09 '15 at 14:58
  • I would have a look at this. http://stackoverflow.com/questions/3288552/how-can-i-escape-an-exclamation-mark-in-cmd-scripts. While in some casees `^^!` is the escape for `!` I am not seeing that interpeted properly. Specifically this response http://stackoverflow.com/a/11228791/3829407 for use that has variable expansion. `!_mailSenderPassword!` – Matt Jul 09 '15 at 15:09

2 Answers2

1

When you are using delayed expansion, then you should avoid percent expansion, else you get problems with carets^ and exclamation marks! and sometimes also with quotes.

As after the percent expansion the content will be parsed for special characters, but after delayed expansion it will be used unchanged.

setlocal EnableDelayedExpansion
set "_mailSenderPassword=12345Aa^!"
call :sendMail
powershell -command "!_mailCommand!"
exit /b

:sendMail
set "_mailCommand=&{$filenameAndPath = '!resultFile!';"
set "_mailCommand=!_mailCommand!$SMTPMessage = New-Object System.Net.Mail.MailMessage('!_mailFrom!', '!_mailTo!', '!_mailSubject!', '!_mailBody!');"
set "_mailCommand=!_mailCommand!$attachment = New-Object System.Net.Mail.Attachment($filenameAndPath);"
set "_mailCommand=!_mailCommand!$SMTPMessage.Attachments.Add($attachment);"
set "_mailCommand=!_mailCommand!$SMTPClient = New-Object Net.Mail.SmtpClient('!_mailHost!', !_mailPort!);"
set "_mailCommand=!_mailCommand!$SMTPClient.EnableSsl = $true;"
set "_mailCommand=!_mailCommand!$SMTPClient.Credentials = New-Object System.Net.NetworkCredential('!_mailFrom!','!_mailSenderPassword!');"
set "_mailCommand=!_mailCommand!$SMTPClient.Send($SMTPMessage)}"
echo !_mailSenderPassword!
exit /b
jeb
  • 78,592
  • 17
  • 171
  • 225
0

The following simplified example worked for me (it successfully echoed 12345Aa^!):

set "_mailSenderPassword=12345Aa^!"

setlocal enabledelayedexpansion
call:sendMail
powershell -command "!_mailCommand!"
endlocal
pause&goto:eof

:sendMail
set "_mailCommand=echo '%_mailSenderPassword%';"
echo %_mailSenderPassword%
echo %_mailCommand%

Note that I had to set _mailSenderPassword before I call setlocal enabledelayedexpansion.

Also there's one funny quirk: you still can get the same result while under enabledelayedexpansion, but you have to use 3 (three) caret characters. E.g. the following will work:

setlocal enabledelayedexpansion
set "_mailSenderPassword=12345Aa^^^!"

call:sendMail
powershell -command "!_mailCommand!"
endlocal
pause&goto:eof

:sendMail
set "_mailCommand=echo '%_mailSenderPassword%';"
echo %_mailSenderPassword%
echo %_mailCommand%
ForNeVeR
  • 6,726
  • 5
  • 24
  • 43