Flutter / googleapis / Gmail API发送电子邮件返回400错误请求

时间:2019-03-08 11:13:27

标签: dart google-api flutter gmail

我在使用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一起正常工作。任何帮助都感激不尽。谢谢。

1 个答案:

答案 0 :(得分:1)

一个古老的但仍然有意义!

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

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

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