【问题标题】:Flutter / googleapis / Gmail API send email returns 400 Bad RequestFlutter / googleapis / Gmail API 发送邮件返回 400 Bad Request
【发布时间】:2019-03-08 11:13:27
【问题描述】:

我在使用 Flutter/Dart 的 googleapis 包时遇到问题。这就是我的代码...

import 'package:googleapis/gmail/v1.dart' as gMail;
import "package:googleapis_auth/auth_io.dart";
import 'package:flutter/services.dart' show rootBundle;

class Example {
  ServiceAccountCredentials credentials;

  Future<gMail.GmailApi> getGMailApi() async {
    return gMail.GmailApi(await getGoogleClient());
  }

  Future<AuthClient> getGoogleClient() async {
    return await clientViaServiceAccount(await getCredentials(), [
      'https://www.googleapis.com/auth/drive',
      'https://mail.google.com/',
    ]);
  }

  Future<ServiceAccountCredentials> getCredentials() async {
    if (credentials == null) {
      credentials = ServiceAccountCredentials.fromJson(
          json.decode(await rootBundle.loadString('GSuiteServiceAccountInfo.json')));
    }

    return credentials;
  }

  String getBase64Email({String source}) {
    List<int> bytes = utf8.encode(source);
    String base64String = base64UrlEncode(bytes);

    return base64StringFormatted;
  }

  sendEmail({
      String from: 'me',
      String to: 'someemail@gmail.com',
      String subject: 'Some subject',
      String contentType: 'text/html',
      String charset: 'utf-8',
      String contentTransferEncoding: 'base64',
      String emailContent: '<table></table>',
  }) async {
    (await getGMailApi()).users.messages.send(
       gMail.Message.fromJson({
         'raw': getBase64Email(
            source: 'From: $from\r\n'
                    'To: $to\r\n'
                    'Subject: $subject\r\n'
                    'Content-Type: $contentType; charset=$charset\r\n'
                    'Content-Transfer-Encoding: $contentTransferEncoding\r\n\r\n'
                    '$emailContent'), // emailContent is HTML table.
       }),
       from);
  }
}

当我调用sendEmail 函数时,我得到DetailedApiRequestError(status: 400, message: Bad Request)。但是,当我尝试通过playground 发送 base64UrlEncoded 字符串时,它可以工作,发送电子邮件。

这是我的flutter doctor -v

[√] Flutter (Channel stable, v1.2.1, on Microsoft Windows [Version 10.0.17763.316], locale en-US)
    • Flutter version 1.2.1 at C:\src\flutter-0.7.3\flutter
    • Framework revision 8661d8aecd (3 weeks ago), 2019-02-14 19:19:53 -0800
    • Engine revision 3757390fa4
    • Dart version 2.1.2 (build 2.1.2-dev.0.0 0a7dcf17eb)

[√] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
    • Android SDK at C:\Users\bbozhidarov\AppData\Local\Android\Sdk
    • Android NDK location not configured (optional; useful for native profiling support)
    • Platform android-28, build-tools 28.0.3
    • ANDROID_HOME = C:\Users\bbozhidarov\AppData\Local\Android\Sdk
    • Java binary at: C:\Program Files\Android\Android Studio\jre\bin\java
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1248-b01)
    • All Android licenses accepted.

[√] Android Studio (version 3.3)
    • Android Studio at C:\Program Files\Android\Android Studio
    • Flutter plugin version 33.3.1
    • Dart plugin version 182.5215
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1248-b01)

[!] IntelliJ IDEA Community Edition (version 2018.1)
    • IntelliJ at C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2018.1.6
    X Flutter plugin not installed; this adds Flutter specific functionality.
    X Dart plugin not installed; this adds Dart specific functionality.
    • For information about installing plugins, see
      https://flutter.io/intellij-setup/#installing-the-plugins

[!] VS Code, 64-bit edition (version 1.30.2)
    • VS Code at C:\Program Files\Microsoft VS Code
    X Flutter extension not installed; install from
      https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter

[√] Connected device (1 available)
    • Android SDK built for x86 • emulator-5554 • android-x86 • Android 8.1.0 (API 27) (emulator)

! Doctor found issues in 2 categories.

这是我的pubspec.yaml

name: App Mobile
description: App Mobile

version: 1.0.0+1

environment:
  sdk: ">=2.0.0-dev.68.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  intl: 0.15.7
  cupertino_icons: 0.1.2
  http: 0.11.3+17
  shared_preferences: ^0.4.2
  google_api_availability: 1.0.4
  geolocator: 2.1.0
  file_picker: 0.1.6
  url_launcher: 4.0.3
  flutter_calendar_carousel: 1.3.10
  date_util: 0.1.4
  permission_handler: 2.1.0
  simple_permissions: 0.1.9
  logging: 0.11.3+2
  googleapis: 0.52.0+1
  uuid: 2.0.0
  googleapis_auth: 0.2.7

dev_dependencies:
  flutter_test:
    sdk: flutter

flutter:
  uses-material-design: true
  assets:
    - assets/email_templates/dynamic_form_email_template.html
    - assets/email_templates/dynamic_form_email_data_row_template.html
    - GSuiteServiceAccountInfo.json

我排除了凭据出现问题的可能性。相同的凭据/帐户/客户端与 DriveApi 配合良好。任何帮助都感激不尽。谢谢。

【问题讨论】:

  • 您解决了这个错误吗?
  • 这方面有什么更新吗?

标签: dart google-api flutter gmail


【解决方案1】:

一个旧的,但仍然相关!

服务帐户 (SA) 需要一个真实的 gsuite 帐户来发送电子邮件,并且 SA 可以模拟该帐户。

解决方案...首先确保您的 SA 在管理控制台的管理 API 访问中具有域范围的委派和邮件发送的授权范围 (https://www.googleapis.com/auth/gmail.send)。然后添加模拟用户变量,为凭据提供现有的 gsuite 电子邮件地址,如下所示:

ServiceAccountCredentials.fromJson(myJsonCredentials, impersonatedUser: "existing_gsuite_email@yourdomain")

【讨论】:

  • 因为这是关于一个颤振应用程序,也许我遗漏了一些东西 - 但是在您分发给用户的客户端应用程序上使用具有这种权限的服务帐户凭据真的是个好主意?
  • @herbert 服务帐户在访问服务时很有用,但您是对的,存在需要管理的固有风险。这是一个完全不同的话题,关于安全实施的 SO 有很多讨论。基本上假设给定足够的时间,没有什么是安全的,并制定了适当的流程来处理发生的违规行为。在上面的代码中,API 凭证存储为资源。虽然这可能只是一个例子,但它绝对不是开始的方式。
猜你喜欢
  • 1970-01-01
  • 2015-06-02
  • 2015-09-21
  • 1970-01-01
  • 2014-07-07
  • 2020-12-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多