使用PowerShell中的Invoke-WebRequest调用Gmail API发送电子邮件

8
$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发送一个格式正确的MIME(符合RFC 2822标准)电子邮件,并对其进行URL安全的base64编码。这个示例应该可以工作,但问题似乎是Gmail实际上不接受这种格式的电子邮件发送。


你尝试过使用这里的PSCmdlets吗?https://github.com/squid808/gShell - Kiran Reddy
我试过了,但它不容易集成到我的项目中,而且我也不需要那里提供的其他谷歌API功能。 - DeepS1X
很不幸,没有人真正完成回答这个问题。 - DeepS1X
你有找到什么东西吗? - DeepS1X
还没有解决方案吗?我也遇到了同样的问题。 - mack
显示剩余3条评论
2个回答

4

有没有不使用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发送电子邮件是明智的,而不是与安全人员争论为什么我们需要在防火墙上开放另一个端口。 - DeepS1X
很不幸,我在这里遇到了一些困难,因为我无法弄清楚我在使用他们提供的REST API时做错了什么。 - DeepS1X
不知道如何使原始代码运行? - DeepS1X

1

经过一段时间的努力,我终于找到了缺失的部分。我没有将我的Base64编码字符串(我的邮件消息)转换为JSON,并且我没有正确地将其包含在Invoke-RestMethod中。

我终于在这里找到了缺失的部分:https://github.com/thinkAmi/PowerShell_misc/blob/master/gmail_api/gmail_sender.ps1。 以下是指引我朝着正确方向前进的代码片段。

$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发送解决方案。我在这个SO问题上找到了一些非常有帮助的代码(代码可以在这里找到),它帮助我获得了正确的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"
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接