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 的动态交易电子邮件的人,这些提示可能会对您有所帮助。我花了一个星期让它工作,这些步骤(和我犯的错误)在各种文档中并不明显:
生成SendGrid API密钥(在SendGrid网站上):生成密钥时,API密钥只出现一次允许您复制它,从那时起它是看不见的。因为后来我看不到密钥,所以我错误地在我的 Heroku 环境变量中使用了 "API Key ID",而不是真正的 API 密钥。
确保您在 Heroku 中给密钥的名称(对我来说:"SENDGRID_APIKEY_GENERAL")与您用来引用它的代码相匹配,即 sg = SendGrid::API.new(api_key: 环境['SENDGRID_APIKEY_GENERAL'])
要发送要在模板中替换的变量,请使用 "dynamic_template_data" 而不是 "substitutions"。这应该在 "personalizations" 部分(参见下面的代码示例)。
我发现在 Heroku 中使用环境变量来引用 Sendgrid 动态模板 ID 很有用(对我来说:'SENDGRID_TRANS_EMAIL_CONFIRM_TEMPLATE_ID'),而不是在 [=] 中使用 hard-coding 97=](只允许我尝试不同的模板而不是更改代码)。
在 Ruby 的 JSON 字符串中使用变量的正确语法是例如"CONFIRM_TOKEN": "'+token+'"(参见下面的代码示例)
不要在名称中使用其他字符:即 "CONFIRM_TOKEN" 有效但“-CONFIRM_TOKEN-”无效
在 SendGrid 上交易电子邮件模板的 HTML 中,使用此语法进行替换:{{CONFIRM_TOKEN}}
在 SendGrid 上创建交易模板时,您只能有一个 'design' 视图或一个 'code' 视图,不能同时有。创建模板时必须在开头select,之后不能切换
在设计 confirmations_instructions 操作中将用户作为记录(例如电子邮件)引用为 record.email
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
我想在用户注册时通过 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 的动态交易电子邮件的人,这些提示可能会对您有所帮助。我花了一个星期让它工作,这些步骤(和我犯的错误)在各种文档中并不明显:
生成SendGrid API密钥(在SendGrid网站上):生成密钥时,API密钥只出现一次允许您复制它,从那时起它是看不见的。因为后来我看不到密钥,所以我错误地在我的 Heroku 环境变量中使用了 "API Key ID",而不是真正的 API 密钥。
确保您在 Heroku 中给密钥的名称(对我来说:"SENDGRID_APIKEY_GENERAL")与您用来引用它的代码相匹配,即 sg = SendGrid::API.new(api_key: 环境['SENDGRID_APIKEY_GENERAL'])
要发送要在模板中替换的变量,请使用 "dynamic_template_data" 而不是 "substitutions"。这应该在 "personalizations" 部分(参见下面的代码示例)。
我发现在 Heroku 中使用环境变量来引用 Sendgrid 动态模板 ID 很有用(对我来说:'SENDGRID_TRANS_EMAIL_CONFIRM_TEMPLATE_ID'),而不是在 [=] 中使用 hard-coding 97=](只允许我尝试不同的模板而不是更改代码)。
在 Ruby 的 JSON 字符串中使用变量的正确语法是例如"CONFIRM_TOKEN": "'+token+'"(参见下面的代码示例)
不要在名称中使用其他字符:即 "CONFIRM_TOKEN" 有效但“-CONFIRM_TOKEN-”无效
在 SendGrid 上交易电子邮件模板的 HTML 中,使用此语法进行替换:{{CONFIRM_TOKEN}}
在 SendGrid 上创建交易模板时,您只能有一个 'design' 视图或一个 'code' 视图,不能同时有。创建模板时必须在开头select,之后不能切换
在设计 confirmations_instructions 操作中将用户作为记录(例如电子邮件)引用为 record.email
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