如何使用 OAuth 2.0 从 Indy 发送 Gmail?

Posted

技术标签:

【中文标题】如何使用 OAuth 2.0 从 Indy 发送 Gmail?【英文标题】:How do I use OAuth 2.0 to send Gmail from Indy? 【发布时间】:2014-12-31 17:50:20 【问题描述】:

以下代码使用 Google 的 Gmail 服务器成功发送了一封电子邮件,但仅在将 Google 帐户安全设置降低为“允许安全性较低的应用程序”之后。

下面提供的代码(最初来自 Remy LeBeau)不​​包含 OAuth 2.0,如果您不想让您的用户做出看似艰难的决定来降低他们的安全设置以使您的应用程序成功,则需要使用 OAuth 2.0。如何将 OAuth 2.0 纳入 Indy 解决方案以满足 Google 更高的安全标准?

工作解决方案:

function TTabbedwithNavigationForm.SendEmailNow(FromStr, ToStr, Subject,
MessageBody, Host: String; Port: Integer; UserName, Pass: String): Boolean;
  begin

///From Remy LeBeau Indy SMTP with SSL via gmail host
Result := False;

try
  IdMessage1 := nil;
  IdSSLIOHandlerSocketOpenSSL1 := nil;
  IdSMTP1 := nil;
  try
    //setup mail message
    try
      IdMessage1                         := TIdMessage.Create(nil);
      IdMessage1.From.Address                := FromStr;//// change to league email
      IdMessage1.Recipients.EMailAddresses   := ToStr;
      IdMessage1.Subject                     := Subject;
      IdMessage1.Body.Text                   := MessageBody;
      //if FileExists(datafilename) then
      //  IdAttachmentFile := TIdAttachmentFile.Create(IdMessage1.MessageParts, datafilename);
    except
      Exception.RaiseOuterException(Exception.Create('Could not create message, please try again later'));
    end;

//setup TLS
try
  IdSSLIOHandlerSocketOpenSSL1                    := TIdSSLIOHandlersocketopenSSL.Create(nil);
  IdSSLIOHandlerSocketOpenSSL1.SSLOptions.Method      := sslvTLSv1;
  IdSSLIOHandlerSocketOpenSSL1.SSLOptions.Mode        := sslmUnassigned;
  IdSSLIOHandlerSocketOpenSSL1.SSLOptions.VerifyMode  := [];
  IdSSLIOHandlerSocketOpenSSL1.SSLOptions.VerifyDepth := 0;
except
  Exception.RaiseOuterException(Exception.Create('Could not create SSL handler, please try again later'));
end; // of try ssl

//setup SMTP
try
  IdSMTP1           := TIdSMTP.Create(nil);
  IdSMTP1.IOHandler := IdSSLIOHandlerSocketOpenSSL1;
  IdSMTP1.UseTLS    := utUseExplicitTLS;
  IdSMTP1.Host      := Host;//'smtp.gmail.com';
  IdSMTP1.Port      := Port;//587;
  IdSMTP1.Username  := UserName;  // 'username@gmail.com';
  IdSMTP1.password  := Pass;  //***gmail account password';
except
  Exception.RaiseOuterException(Exception.Create('Could not create SMTP handler, please try again later'));
end; // of try

try
  IdSMTP1.Connect;
  try
    IdSMTP1.Send(IdMessage1) ;
  finally
    IdSMTP1.Disconnect;
  end;
except
  Exception.RaiseOuterException(Exception.Create('Could not send secure email, please try again later'));
end;
  finally
    IdSMTP1.Free;
    IdSSLIOHandlerSocketOpenSSL1.Free;
    IdMessage1.Free;
    Result := True;
  end;
except
  on E: Exception do
  begin
    if E.InnerException <> nil then
      ShowMessage('ERROR: ' + E.Message + #13#13 + E.InnerException.Message)
    else
      ShowMessage('ERROR: ' + E.Message);
  end;
end;

/// End Remy LeBeau Code

end;

【问题讨论】:

你检查过this thread和this project吗? 我在我的 Gmail 帐户上启用了两步验证(这会禁用“允许不太安全的应用程序”选项),并且我可以使用 Google 应用程序密码而不是 OAuth 使用 Indy 登录到 Gmail . 嘿,我已经在与原始解决方案的作者交谈了——非常酷。在我的应用程序成功之前,我不愿依赖任何要求用户更改其 Google 帐户设置的解决方案。如果在我的 Delphi XE5 移动应用程序中添加 Google 应用程序密码意味着用户不必对他们的 Google 帐户进行任何更改 - 那么这将是一个很好的解决方案。您能解释一下如何将 Google 应用密码添加到 Delphi 项目或 SMTP 组件属性吗? 您没有为您的项目 ImageBase 添加密码。相反,您继续请求 用户的 密码,与往常一样。但是,用户提供的不是常规密码,而是用户generates under his or her account's security settings 的应用程序专用密码。例如,我的旧 android 手机有一个应用专用密码,因为它的帐户设置早于 Google 的两步 OAuth 机制。 Leonardo Herrera 的评论非常有助于更好地理解将 OAuth 2 与 Indy 组件结合所需的工作。不幸的是,演示的组件是 IMAP,而不是 SMTP。我的要求是发送电子邮件,而不是从帐户的收件箱中获取/阅读电子邮件。 【参考方案1】:

你需要导入lib BackgroundMailLibrary

BackgroundMail bm = new BackgroundMail(PasswordChangeActivity.this);
                                            bm.setGmailUserName(mail id);
                                            bm.setGmailPassword(Utils.decryptIt(password)); 
                                            bm.setMailTo(ownerEmail);
                                            bm.setFormSubject(subject);
                                            bm.setFormBody(body);
                                            bm.send();

【讨论】:

以上是关于如何使用 OAuth 2.0 从 Indy 发送 Gmail?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用带有 AsynceTask 的 Oauth 2.0 向自定义 api 发送 http 请求

如何从单页应用程序实现 OAuth 2.0 授权码授予?

2-legged oauth 在 OAuth 2.0 中如何工作?

Postman-OAuth 2.0授权

GTM-OAuth 2.0 多个发布数据参数?

需要Google OAuth 2.0架构建议通过Java邮件Api发送Smtp邮件