Sendgrid v3 不适用于 rails my_mailer.rb

Sendgrid v3 not working for me with rails my_mailer.rb

我想在用户注册时通过 Sendgrid 发送交易邮件(我使用 devise 进行身份验证)。我使用 SMTP 在 my_mailer.rb 中正常工作,如下所示:

  def confirmation_instructions(record, token, opts={})
    # SMTP header for Sendgrid - v2
    # headers["X-SMTPAPI"]= {
    #  "sub": {
    #    "-CONFIRM_TOKEN-": [
    #      token
    #    ]       
    #   },
    #  "filters": {
    #   "templates": {
    #     "settings": {
    #       "enable": 1,
    #       "template_id": "1111111-1111-1111-1111-111111111111"
    #     }
    #   }
    #  }   
    # }.to_json    

但是,由于 Sendgrid 提示使用 v3 语法来支持较新的邮件模板,我将代码更改为以下内容(来自 sendgrid 帮助文档,而不是真正的理解):

  def confirmation_instructions(record, token, opts={})

    require 'sendgrid-ruby'
    include SendGrid

    sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY'])

    data = JSON.parse('{
      "substitutions": {
        "-CONFIRM_TOKEN-": [
          token
        ],
      "template_id": "1111111-1111-1111-1111-111111111111"
    }')

    response = sg.client.mail._("send").post(request_body: data)
    puts response.status_code
    puts response.body
    puts response.parsed_body
    puts response.headers    

现在我收到错误消息:
'NoMethodError (undefined method `include' for #<MyMailer:0x0000000003cfa398>):'

如果我注释掉 'include' 行,我得到:
'TypeError (no implicit conversion of nil into String):' on the line: "sg = SendGrid..."

我用的是Gem:sendgrid-ruby (5.3.0)

任何想法都将不胜感激 - 我一直试图通过反复试验找到正确的语法,现在终于承认我被卡住了。

更新#1:
第一个问题是我使用了错误的 API_KEY 环境。变量(从 2 个不同的帮助文档中复制):"SENDGRID_API_KEY"(在代码中)与 SENDGRID_APIKEY_GENERAL(在 Heroku 中设置)。固定。

更新#2:
随着 "include" 行被注释掉,我现在似乎得到了 JSON 解析错误:

JSON::ParserError (416: unexpected token at 'token

所以我当前的 2 个问题是:
(1) 我希望 'token' 成为确认令牌变量,但它没有被传递

(2) 发送 'data' 的以下简单(1 行)内容不会引发错误,但 Sendgrid 中的相应模板不是 selected:

data = JSON.parse('{
  "template_id": "1111111-1111-1111-1111-111111111111"    
}')

更新#3:
这是关于我的问题状态的更新以及我现在遇到的问题:

这段代码工作正常(使用我正在尝试升级的 Sendgrid v2):

  def confirmation_instructions(record, token, opts={})

    #
    # SMTP header for Sendgrid     - v2
    #     This works fine
    #

    headers["X-SMTPAPI"]= {
     "sub": {
       "-CONFIRM_TOKEN-": [
         token
       ]
      },
     "filters": {
      "templates": {
        "settings": {
          "enable": 1,
          "template_id": "1111111-1111-1111-1111-111111111111"
        }
      }
     }
    }.to_json 

此 Sendgrid v3 代码不起作用(电子邮件确实通过 Sendgrid 发送,但它不 select Sendgrid 中的模板 - 它只使用 app/views/my_mailer/confirmation_instructions.[=69 中的任何代码=]):

    #
    # Sendgrid API v3
    #   This sends an email alright but it takes content from app/views/my_mailer/confirmation_instructions.html.erb
    #   It DOES NOT select the template within Sendgrid
    #

    data = JSON.parse('{
      "template_id": "1111111-1111-1111-1111-111111111111",
      "personalizations": [
        {
          "substitutions": {
            "-CONFIRM_TOKEN-": "'+token+'"
          } 
        }
      ]
    }')

    sg = SendGrid::API.new(api_key: ENV['SENDGRID_APIKEY_GENERAL2'])
    response = sg.client.mail._("send").post(request_body: data)
    puts response.status_code
    puts response.body
    puts response.parsed_body
    puts response.headers

一如既往,欢迎任何见解。

您不能 include 方法中的模块。你必须将它包含在你的 class 中,所以在方法之外,比如

class SomethingMailer
  require 'sendgrid-ruby'
  include SendGrid

  def confirmation_instructions(record, token, opts={})
    ...
  end
end

对于您的第三次更新问题:

您不是在发送 JSON,而是在创建 JSON,然后将其解析为散列,然后发送该散列,而不是 JSON。

JSON.parse #parses a JSON into a Hash

您应该反其道而行之,将哈希转换为 JSON

类似

data = {
  template_id: your_template_id # or pass a string
  personalizations: [
    ...
  ]
}

那你打电话

data_json = data.to_json
response = sg.client.mail._("send").post(request_body: data_json)

然而,这并不能解释为什么您在 app/views/my_mailer/confirmation_instructions.html.erb 中的模板会被发送。所以我认为您要么同时调用不同的 mailer_method,要么根本不调用实际的 confirmation_instructions 方法。尝试确认您的 SendGrid 方法确实被调用并查看它是什么 returns。它应该在您发送哈希而不是字符串之前返回某种错误。

对于任何试图让 SendGrid v3 API 与 Ruby/Devise/Heroku 一起工作并使用 SendGrid 的动态交易电子邮件的人,这些提示可能会对您有所帮助。我花了一个星期让它工作,这些步骤(和我犯的错误)在各种文档中并不明显:

  1. 生成SendGrid API密钥(在SendGrid网站上):生成密钥时,API密钥只出现一次允许您复制它,从那时起它是看不见的。因为后来我看不到密钥,所以我错误地在我的 Heroku 环境变量中使用了 "API Key ID",而不是真正的 API 密钥。

  2. 确保您在 Heroku 中给密钥的名称(对我来说:"SENDGRID_APIKEY_GENERAL")与您用来引用它的代码相匹配,即 sg = SendGrid::API.new(api_key: 环境['SENDGRID_APIKEY_GENERAL'])

  3. 要发送要在模板中替换的变量,请使用 "dynamic_template_data" 而不是 "substitutions"。这应该在 "personalizations" 部分(参见下面的代码示例)。

  4. 我发现在 Heroku 中使用环境变量来引用 Sendgrid 动态模板 ID 很有用(对我来说:'SENDGRID_TRANS_EMAIL_CONFIRM_TEMPLATE_ID'),而不是在 [=] 中使用 hard-coding 97=](只允许我尝试不同的模板而不是更改代码)。

  5. 在 Ruby 的 JSON 字符串中使用变量的正确语法是例如"CONFIRM_TOKEN": "'+token+'"(参见下面的代码示例)

  6. 不要在名称中使用其他字符:即 "CONFIRM_TOKEN" 有效但“-CONFIRM_TOKEN-”无效

  7. 在 SendGrid 上交易电子邮件模板的 HTML 中,使用此语法进行替换:{{CONFIRM_TOKEN}}

  8. 在 SendGrid 上创建交易模板时,您只能有一个 'design' 视图或一个 'code' 视图,不能同时有。创建模板时必须在开头select,之后不能切换

  9. 在设计 confirmations_instructions 操作中将用户作为记录(例如电子邮件)引用为 record.email

  10. Gemfile: gem 'rails', '5.2.2' ruby '2.6 .1' gem 'devise', '4.6.1' gem 'sendgrid-ruby', '6.0.0'

这是我在 my_mailer.rb 中获得的成功 ruby 代码:

  def confirmation_instructions(record, token, opts={})

    data = JSON.parse('{
      "personalizations": [
        {
          "to": [
            {
              "email": "'+record.email+'"
            }
          ],
          "subject": "Some nice subject line content",
          "dynamic_template_data": {
            "CONFIRM_TOKEN": "'+token+'",
            "TEST_DATA": "hello"
          }
        }
      ],
      "from": {
        "email": "aaaa@aaaa.com"
      },
      "content": [
        {
          "type": "text/plain",
          "value": "and easy to do anywhere, even with Ruby"
        }
      ],
      "template_id": "'+ENV['SENDGRID_TRANS_EMAIL_CONFIRM_TEMPLATE_ID']+'"
    }')

    sg = SendGrid::API.new(api_key: ENV['SENDGRID_APIKEY_GENERAL'])
    response = sg.client.mail._("send").post(request_body: data)
    puts response.status_code
    puts response.body
    puts response.headers