使用 Gmail API 在 Powershell 中使用 Invoke-WebRequest 发送电子邮件
Posted
技术标签:
【中文标题】使用 Gmail API 在 Powershell 中使用 Invoke-WebRequest 发送电子邮件【英文标题】:Using Gmail API to send an email using Invoke-WebRequest in Powershell 【发布时间】:2017-06-14 11:59:32 【问题描述】:$firstEmail = "joe@gmail.com";
$secondEmail = "notjoe@gmail.com";
Function Set-MIMEBase64Encoded
Param(
[string]$subject
)
#Creates a MIME formatted email.
$text = "From: $firstEmail\r\n" + "To: $secondEmail\r\n" + "Subject: $subject\r\n\r\n" + "$subject";
$bytes = [System.Text.Encoding]::Unicode.GetBytes($text);
#Converts to Base 64.
$encodedText =[Convert]::ToBase64String($bytes);
#Makes encoding URL safe.
$urlSafe1 = $encodedText.replace('+', '-');
$urlSafe2 = $urlSafe1.replace('/', '_');
$urlSafe3 = $urlSafe2.replace('=', '*');
return $urlSafe3;
Function Mail-Output
Param(
[String]$subject
)
#Acquires access token.
$accessToken = Refresh-AccessToken;
#Sends subject for MIMEB64 encoding
$text = Set-MIMEBase64Encoded -subject $subject;
#Requests sends email according to parameters.
$messages = Invoke-WebRequest -Uri ("https://www.googleapis.com/gmail/v1/users/me/messages/send?access_token=$accessToken&raw=$text") -Method Post;
Write-Output $messages
Mail-Output -subject "Hope this works!"
所以,我在这里要做的是通过 Powershell 中的 Invoke-WebRequest 发送以 URL 安全 base64 编码的格式正确的 MIME(符合 RFC 2822)电子邮件。此示例应该可以工作,但问题似乎是 Gmail 实际上不接受以这种格式发送的电子邮件。
【问题讨论】:
您是否尝试过在此处使用 pscmdlet:github.com/squid808/gShell 我做了,但它不容易集成到我的项目中,我也不需要那里提供的其他 google API 功能。 不幸的是,实际上没有人回答完这个问题。 试试这个support.google.com/accounts/answer/6010255?hl=en 启用不太安全的应用程序来使用它不是问题。显然,我可以使用 SMTP 并将登录凭据明文放入脚本中。但如果我可以使用 gmail API 提供的方法发送消息,它会更安全(通过使用 google-OAuth),并且不需要更改防火墙以允许 SMTP。 【参考方案1】:有什么理由不使用Send-MailMessage
吗?如果没有,你可以试试这个例子:
$From = "YourEmail@gmail.com"
$To = "AnotherEmail@YourDomain.com"
$Cc = "YourBoss@YourDomain.com"
$Attachment = "C:\temp\Some random file.txt"
$Subject = "Email Subject"
$Body = "Insert body text here"
$SMTPServer = "smtp.gmail.com"
$SMTPPort = "587"
Send-MailMessage -From $From -to $To -Cc $Cc -Subject $Subject `
-Body $Body -SmtpServer $SMTPServer -port $SMTPPort -UseSsl `
-Credential (Get-Credential) -Attachments $Attachment
【讨论】:
原因是我无法在我们的组织内使用 SMTP(除 80 和 443 之外的所有端口都被防火墙阻止),并且由于我已经使用 API 进行了电子邮件删除和检索,所以我谨慎的做法是尝试将其扩展到通过端口 80/443 发送电子邮件,而不是与安全人员争论为什么我们需要在防火墙内打开另一个端口。 不幸的是,我似乎在这里遇到了一些障碍,因为我无法完全弄清楚我在使用他们提供的 REST API 时做错了什么。 不知道如何使原始代码发挥作用?【参考方案2】:在研究了一段时间后,我终于找到了丢失的部分。我没有将我的 Base64 编码字符串(我的邮件消息)转换为 JSON,也没有正确地将它包含在 Invoke-RestMethod 中。
我终于在这里找到了缺失的部分:https://github.com/thinkAmi/PowerShell_misc/blob/master/gmail_api/gmail_sender.ps1。 这是给我指明正确方向的 sn-p。
$body = @ "raw" = $raw; | ConvertTo-Json
$uri = "https://www.googleapis.com/gmail/v1/users/me/messages/send?access_token=$AccessToken"
$result = Invoke-RestMethod $uri -Method POST -ErrorAction Stop -Body $body -ContentType "application/json"
一旦有了它,我就能够拼凑出一个使用 Powershell 通过 Gmail API 发送的解决方案。
我在 this SO question 上找到了一些非常有用的代码(代码可以在 here 找到),它们帮助我获得了正确的 OAuth 访问令牌。
这是一个可行的解决方案(需要清理):
Function Encode-Base64Url([string]$MsgIn)
$InputBytes = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($MsgIn))
# "Url-Safe" base64 encodeing
$InputBytes = $InputBytes.Replace('+', '-').Replace('/', '_').Replace("=", "")
return $InputBytes
Add-Type -Path "C:\path\to\AE.Net.Mail.dll" # We are using AE.Net.Mail to create our message. https://github.com/andyedinborough/aenetmail
Add-Type -AssemblyName System.IO
Add-Type -AssemblyName System.Text.Encoding
$ToEmail = "someone@somewhere.com"
$FromEmail = "a.person@gmail.com"
# From https://gist.github.com/LindaLawton/55115de5e8b366be3969b24884f30a39
# Setup:
#
# Step 1: create new project on https://console.developers.google.com.
# Step 2: Create oauth credentials type native or other.
# Save the client id and secret.
# Step 3: Enable the api you are intersted in accessing.
# Look up what scopes you need for accssing this api,
# Step 4: Using the client id, and client secret from the
#
#
# Inital Authenticate: Authentication must be done the first time via a webpage create the link you will need. More then one scope can be added simply by seporating them with a comama
# Place it in a webbrowser.
#
# https://accounts.google.com/o/oauth2/auth?client_id=CLIENT ID&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=SCOPES&response_type=code
# Change Scopes to https://www.googleapis.com/auth/gmail.send
# https://www.googleapis.com/auth/gmail.readonly
# https://mail.google.com/
#
# Copy the authencation code and run the following script.
# note: AuthorizationCode can only be used once you will need to save the refresh token returned to you.
$ClientID = "Your Client ID"
$secret = "Your Client Secret"
$RedirectURI = "urn:ietf:wg:oauth:2.0:oob"
$AuthorizationCode = 'Your Authorization Code'
$tokenParams = @
client_id=$ClientID;
client_secret=$secret;
code=$AuthorizationCode;
grant_type='authorization_code';
redirect_uri=$RedirectURI
$token = Invoke-WebRequest -Uri "https://accounts.google.com/o/oauth2/token" -Method POST -Body $tokenParams | ConvertFrom-Json
# Use refresh token to get new access token
# The access token is used to access the api by sending the access_token parm with every request.
# Access tokens are only valid for an hour, after that you will need to request a new one using your refresh_token
$refreshToken = $token.refresh_token
$RefreshTokenParams = @
client_id=$ClientID;
client_secret=$secret;
refresh_token=$refreshToken;
grant_type='refresh_token';
$RefreshedToken = Invoke-WebRequest -Uri "https://accounts.google.com/o/oauth2/token" -Method POST -Body $refreshTokenParams | ConvertFrom-Json
$AccessToken = $RefreshedToken.access_token
# Compose and send an email using the access token
$From = New-Object MailAddress($FromEmail)
$To = New-Object MailAddress($ToEmail)
$Msg = New-Object AE.Net.Mail.MailMessage
$Msg.To.Add($To)
$Msg.ReplyTo.Add($From) # Important so email doesn't bounce
$Msg.From = $From
$Msg.Subject = "Sent through the Gmail API using Powershell"
$Msg.Body = "Hello, world from Gmail API using Powershell!"
$MsgSW = New-Object System.IO.StringWriter
$Msg.Save($MsgSW)
$EncodedEmail = Encode-Base64Url $MsgSW
# Found this gem here: https://github.com/thinkAmi/PowerShell_misc/blob/master/gmail_api/gmail_sender.ps1
$Content = @ "raw" = $EncodedEmail; | ConvertTo-Json
$Result = Invoke-RestMethod -Uri "https://www.googleapis.com/gmail/v1/users/me/messages/send?access_token=$AccessToken" -Method POST -ErrorAction Stop -Body $Content -ContentType "Application/Json"
if($Result)
Write-Host $Result
else
Write-Host "Error sending email"
【讨论】:
以上是关于使用 Gmail API 在 Powershell 中使用 Invoke-WebRequest 发送电子邮件的主要内容,如果未能解决你的问题,请参考以下文章
使用 PowerShell V2 的 Send-MailMessage 通过 Gmail 发送邮件
在java中使用对象com.google.api.services.gmail.model.Message读取gmail消息正文?