Saltar para a documentação
Ruby

Enviar um email

`emails.send`: uma mensagem, agora ou mais tarde.

emails.send

send_email.rb
email = client.emails.send(  from: {email: "[email protected]", name: "Acme Billing"},  to: ["[email protected]", "Grace <[email protected]>"],  cc: "[email protected]",  bcc: [{email: "[email protected]"}],  replyTo: "[email protected]",  subject: "Your September invoice",  html: "<p>Invoice attached.</p>",  text: "Invoice attached.",  headers: {"X-Campaign" => "invoices"},  attachments: [{filename: "invoice.pdf", content: Pathname("invoice.pdf")}],  threadId: "CAHk7pQ2x9LmZ4-mail.example.com",  scheduledAt: "PT1H",  tags: {order: "4021"},  tracking: {opens: true, clicks: true}) puts email[:id], email[:status]

to, cc e bcc aceitam um destinatário ou um Array deles, e um único é envolvido automaticamente. Cada um pode ser um endereço simples, Name <addr@host> ou um Hash com email e name.

A mensagem é passada como argumentos nomeados ou como um único Hash. Os argumentos nomeados ao lado de um Hash fundem-se com ele e prevalecem quando ambos indicam um campo, por isso client.emails.send(message, subject: "Re: your invoice") altera um campo de uma mensagem que construiu antes. As chaves mantêm os nomes da API, e é por isso que replyTo e scheduledAt continuam em camelCase, enquanto idempotency_key: e api_key: são opções da chamada e nunca fazem parte da mensagem.

Parâmetros

fromString or Hashobrigatório
O remetente. Um endereço simples, `Name <addr@host>`, ou um Hash com `email` e `name`. Tem de ser um a partir do qual esta chave possa enviar, ou a chamada lança um 403 `from_address_forbidden`. Não há remetente alternativo, por isso um envio indica sempre o endereço de onde sai.
toString, Hash or Arrayobrigatório
Um destinatário ou um Array deles, e um único é envolvido automaticamente. No máximo 50 no total de `to`, `cc` e `bcc`, e mais do que isso é um 422 `too_many_recipients`.
ccString, Hash or Array
Conta para o limite de 50 destinatários.
bccString, Hash or Array
Nunca aparece nos bytes que qualquer outra pessoa recebe, porque é transmitido um envelope por destinatário. Também conta para os 50.
replyToString or Hash
Um único endereço, enviado como cabeçalho Reply-To.
subjectString
No máximo 998 caracteres, o limite de linha do RFC 5322. Vazio por omissão, e um assunto vazio recorre ao do modelo ou ao do rascunho.
htmlString
É obrigatório um de `html`, `text`, `draftId` ou `template`. O HTML é o que os destinatários veem quando `html` e `text` são ambos fornecidos. No máximo 1 000 000 de caracteres.
textString
A parte de texto simples, no máximo 1 000 000 de caracteres.
templateHash
Renderizar um modelo guardado no servidor: um Hash com `id`, que aceita um id ou um slug, e `version` (um Integer), `props` e `slots` opcionais. `version` fixa uma revisão. Omita-o para usar a que estiver publicada quando o pedido for aceite. Uma prop desconhecida ou em falta dá 422 em vez de um espaço em branco na mensagem.
draftIdString
Enviar um rascunho guardado com este envelope, tal como foi escrito. Não pode ser combinado com `template` nem com `translate`.
headersHash
Nome de cabeçalho para valor String, limitado a `X-*`, `List-*`, Reply-To, Precedence, Auto-Submitted, Importance, Priority e Feedback-ID. Tudo o que o transporte define por si próprio é recusado com um 422 `reserved_header` em vez de ser descartado silenciosamente.
attachmentsArray<Hash>
Cada um é um Hash com `filename`, `content` e um `contentType` opcional, ou um Hash só com `fileId`, que refere um ficheiro já existente no espaço de trabalho, como um de `files.upload`. Passe bytes em `content` e são codificados em base64 automaticamente. 20 ficheiros, com os ficheiros inline limitados a 5 MB no total depois de descodificados. Um ficheiro guardado pode ser maior e segue como ligação de transferência.
attachmentDeliveryString
`mime`, `link` ou `auto`. `auto` envia os ficheiros como ligações de transferência quando ultrapassam 2 MB num domínio com um domínio de ficheiros ativo, e dentro da mensagem nos restantes casos. Se for omitido, aplica-se a definição da caixa de correio, cuja predefinição é `auto`.
threadIdString
Responder numa conversa existente. O transporte escreve In-Reply-To e References.
scheduledAtTime, DateTime or String
Um Time ou um DateTime, enviado como instante ISO 8601 em UTC, um instante ISO 8601 como String, ou uma duração como `PT1H`. Até um ano no futuro, nunca no passado. Não pode ser combinado com `cancellableForSeconds`. Uma Date do Ruby é enviada como uma data simples, que a API lê como meia-noite UTC desse dia, por isso passe um Time quando a hora importa.
cancellableForSecondsInteger
De 0 a 900. Uma janela para anular num envio imediato: o mecanismo de anulação do editor de mensagens, exposto em vez de fixo no código.
tagsHash
Até 10 etiquetas, com chaves de 1 a 64 letras, algarismos, `_` ou `-` e valores String de até 256 caracteres. Devolvidas tal como estão em cada leitura e nunca interpretadas.
signatureBoolean
Se esta mensagem leva a assinatura do endereço de onde é enviada: a dele, senão a do catch-all para um endereço que um catch-all apanhou, senão o rodapé do OpenEmail, a menos que esse endereço o tenha desligado. Se for omitido, um corpo `html` sai exatamente como foi escrito, sem assinatura, e um corpo só `text` leva-a. Defina `false` no correio que um programa envia em nome de alguém, como um recibo, uma reposição de palavra-passe ou um resumo, nenhum dos quais quer a assinatura de uma pessoa por baixo. Os envios com modelo e os envios cifrados nunca a levam.
trackingHash
Um Hash com os Boolean opcionais `opens` e `clicks`: indica se deve ser adicionado um píxel de abertura e se as ligações desta mensagem devem ser reescritas. Inativo a menos que o rastreio tenha sido ativado para o endereço a partir do qual é enviada (ou para o catch-all que o apanhou), e qualquer uma das chaves indicadas aqui decide para essa mensagem, independentemente da definição do endereço.
translateHash
Enviar na língua do destinatário: um Hash com `to` e `from`, `subject` e `includeOriginal` opcionais. `to` aceita um código, um nome em inglês ou o nome da língua na própria língua, e `subject` e `includeOriginal` são ambos true por predefinição. Resolvido quando o pedido é aceite, pelo que uma mensagem agendada leva as palavras que foram aprovadas. Recusado em conjunto com `draftId`.
idempotency_keyString
A sua própria chave para este envio, de 1 a 255 caracteres entre letras, algarismos, `_`, `.`, `:` ou `-`. Sem ela, o cliente gera uma chave para cada chamada, por isso as suas próprias repetições nunca enviam duas vezes, e com ela um envio que corre de novo noutro processo é reproduzido em vez de repetido.
api_keyString
Envia com esta chave em vez da do cliente, para um processo que envia em nome de vários espaços de trabalho.

Resposta

Um Hash com chaves Symbol, por isso email[:status] lê o estado.

idString
O id do envio, `msg_` seguido de 24 caracteres hexadecimais. Use-o para `get`, `cancel`, `reschedule` e `get_tracking`.
statusString
queued, scheduled, sending, sent, partial, bounced, cancelled ou failed. Leia este campo em vez de se basear no facto de a chamada ter terminado: um envio imediato é despachado dentro do pedido e normalmente volta como `sent`, `partial` ou `failed`, e um retido volta como `queued` ou `scheduled`. `partial` é um estado próprio: alguns destinatários já a têm e não é possível anular o envio, pelo que tentar de novo é errado e reportar falha é falso.
modeString
`live` ou `test`: que tipo de chave o enviou. Um envio de teste é registado e nunca transmitido. Aparece como `sent`, com `transport` igual a `test`, por isso verifique a resposta e não uma caixa de entrada.
fromString
O endereço efetivamente autorizado e colocado na linha, que nem sempre é o que foi pedido.
subjectString or nil
Tal como foi enviado.
messageIdString or nil
O Message-ID RFC 5322. nil até o MIME existir. O serviço de envio reescreve o cabeçalho à saída, por isso nenhuma devolução nem relatório de entrega transporta este valor. É em `id` que um evento regressa.
threadIdString or nil
A thread em que ficou.
transportString or nil
Como a mensagem saiu. nil até ao despacho.
attemptsInteger
Quantas vezes o despacho foi tentado.
lastErrorString or nil
Porque falhou a última tentativa, literalmente.
scheduledAtString or nil
O instante ISO 8601 em que deve sair.
cancellableUntilString or nil
Enquanto o momento atual for anterior a este, `cancel` continua a funcionar.
sentAtString or nil
O instante ISO 8601 em que saiu.
tagsHash
O que enviou, devolvido tal e qual.
sourceString
composer, api, mcp, ai ou queue: que superfície o pediu. `api` é este cliente.
createdAtString
O instante ISO 8601 em que o registo foi escrito.
replayedBoolean
True quando uma Idempotency-Key correspondeu a um envio que já existia. Nada de novo foi enviado, e esta é a mensagem original tal como está agora.
translationHash
Presente apenas numa mensagem que foi traduzida, e apenas onde todo o pedido guardado é transportado: esta resposta e `get`. Contém `language`, `languageName`, `detectedSourceLanguage`, `subject` e `includeOriginal`, com códigos em vez de linhas de idioma completas. Uma linha de listagem nunca o tem, por isso a sua ausência aí não diz nada num sentido nem no outro.

Na língua do destinatário

translate escreve a mensagem na língua de outra pessoa antes de ela partir. O corpo, e o assunto a menos que o desative, é traduzido quando a API aceita o pedido, e o que saiu é o que vai sair: uma tradução que não pôde ser produzida recusa o envio em vez de o publicar na língua em que o escreveu.

translate.rb
email = client.emails.send(  from: "[email protected]",  to: "[email protected]",  subject: "Your September invoice",  html: "<p>Invoice attached. Payment is due on the 14th.</p>",  translate: {to: "de"}) p email[:translation]

email[:translation] contém então {language: "de", languageName: "German", detectedSourceLanguage: "en", subject: true, includeOriginal: true}.

Ninguém leu aquilo antes de partir. emails.translate é a mesma ida e volta parada um passo antes. Mostre-a a uma pessoa, deixe-a alterá-la e depois envie o que ela aprovou sem qualquer translate na chamada. Passá-lo outra vez traduziria uma segunda vez e deitaria fora as edições dela.

preview_translation.rb
preview = client.emails.translate(  subject: "Your September invoice",  html: "<p>Invoice attached. Payment is due on the 14th.</p>",  to: "de") puts preview.dig(:language, :native), preview[:subject], preview[:html]print "Send it as it is? [y/N] " if $stdin.gets.to_s.strip.casecmp?("y")  client.emails.send(    from: "[email protected]",    to: "[email protected]",    subject: preview[:subject],    html: preview[:html]  )end
languages.rb
p OpenEmail::LANGUAGES.size current = client.languages.listp current.size p OpenEmail.resolve_language("Deutsch")&.fetch(:code)p OpenEmail.resolve_language("zh-TW")&.fetch(:code)p OpenEmail.language_by_code("DE")&.fetch(:native)p OpenEmail.rtl_language?("ar")

Essas linhas de código imprimem 200, o número de linhas com que esta versão vem, depois quantas a API tem agora, e depois "de", "zh-Hant", "Deutsch" e true. A tabela vem incluída, pela ordem do seletor, como OpenEmail::LANGUAGES, um Array congelado de Hashes com code, label, native, flag e rtl, para que um seletor possa ser preenchido antes do primeiro pedido. languages.list devolve as mesmas linhas vindas da rede sob a forma de um Array simples, para quem prefira as atuais às que esta versão trouxe. OpenEmail.resolve_language aceita um código, um nome em inglês, um endónimo ou um alias (zh-TW é um alias de um código que já não é listado) e devolve nil quando nada corresponde, OpenEmail.language_by_code faz corresponder um código exato sem distinguir maiúsculas de minúsculas, e dezasseis das linhas são da direita para a esquerda. Pesquise native, label e code em conjunto, mostre native primeiro e guarde o código.

emails.translate não é repetido automaticamente. Gasta chamadas ao modelo e não escreve nada, por isso não há nada para tornar idempotente e uma repetição após um pedido sem resposta só compraria a mesma resposta duas vezes.

  • Um idioma que a API não consegue identificar é um validation_error em translate.to, antes de seja o que for ser enviado.
  • translation_too_long acima de 30 000 caracteres, translation_not_configured quando a instalação não tem IA configurada, um 429 ai_quota_exceeded quando o espaço de trabalho já gastou as ações de IA de hoje (é reposta à meia-noite UTC e não é repetido), translation_failed quando o fornecedor não respondeu. Nenhum deles envia a mensagem por traduzir como alternativa.
  • Funciona com template: é o resultado RENDERIZADO que é traduzido, por isso um corpo guardado serve todas as línguas em que os seus clientes leem. Um template que renderiza um documento inteiro mantém o seu doctype, os seus blocos <style> e as suas regras @font-face: só o corpo vai para o modelo e o resto é reposto à volta dele. O seu <title> fica intacto, e nada o mostra de qualquer forma.
  • Uma repetição não custa nada a mais. A tradução não faz parte da impressão digital de idempotência (o pedido faz, translate incluído), por isso repetir um envio sem resposta com a mesma Idempotency-Key reproduz a mensagem que já existe em vez de traduzir e enviar uma segunda.
  • Uma mensagem traduzida que esteja em fila ou agendada mantém o texto aprovado. emails.reschedule continua a movê-la, enquanto emails.update recusa um texto novo com um 409 translation_locked, por isso mudar o que diz significa cancelar e enviar de novo.

Anexos

content segue em base64 pela rede. Passe os bytes e são codificados automaticamente: uma String binária como a que File.binread devolve, um IO como um File aberto, ou um Pathname, que é lido automaticamente.

attachments.rb
attachments = [  {filename: "invoice.pdf", content: File.binread("invoice.pdf"), contentType: "application/pdf"},  {filename: "report.pdf", content: Pathname("report.pdf")},  {fileId: "file_6bb640f5b99e47deb758f1f5"}] client.emails.send(  from: "[email protected]",  to: "[email protected]",  subject: "Your documents",  text: "Both are attached.",  attachments:)

Uma String marcada como texto, como a que File.read devolve, é tomada como já estando em base64, e uma que não esteja em base64 lança ArgumentError antes de qualquer envio. Leia os ficheiros com File.binread, ou chame .b sobre os bytes que chegaram marcados como texto.

OpenEmail.to_base64 está disponível se precisar da mesma codificação noutro sítio. Aceita uma String binária, um IO ou um Pathname e devolve base64 estrito, sem quebras de linha.