{"id":20564430,"url":"https://github.com/tarantool/smtp","last_synced_at":"2025-06-13T20:06:49.390Z","repository":{"id":39707951,"uuid":"106016020","full_name":"tarantool/smtp","owner":"tarantool","description":"Send email via SMTP from Tarantool","archived":false,"fork":false,"pushed_at":"2025-04-03T10:32:36.000Z","size":120,"stargazers_count":8,"open_issues_count":3,"forks_count":3,"subscribers_count":28,"default_branch":"master","last_synced_at":"2025-04-14T15:12:55.074Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tarantool.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-10-06T14:46:30.000Z","updated_at":"2025-04-03T10:32:40.000Z","dependencies_parsed_at":"2024-03-14T14:28:57.974Z","dependency_job_id":"9a9a7c9d-cc89-46d3-92ee-be948fd345b0","html_url":"https://github.com/tarantool/smtp","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/tarantool/smtp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tarantool%2Fsmtp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tarantool%2Fsmtp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tarantool%2Fsmtp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tarantool%2Fsmtp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tarantool","download_url":"https://codeload.github.com/tarantool/smtp/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tarantool%2Fsmtp/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259712410,"owners_count":22900038,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-16T04:26:36.532Z","updated_at":"2025-06-13T20:06:49.370Z","avatar_url":"https://github.com/tarantool.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ca href=\"http://tarantool.org\"\u003e\n\t\u003cimg src=\"https://avatars2.githubusercontent.com/u/2344919?v=2\u0026s=250\" align=\"right\"\u003e\n\u003c/a\u003e\n\u003c!--\n\u003ca href=\"https://travis-ci.org/tarantool/smtp\"\u003e\n\t\u003cimg src=\"https://travis-ci.org/tarantool/smtp.png?branch=master\" align=\"right\"\u003e\n\u003c/a\u003e\n--\u003e\n\n# SMTP client for Tarantool 1.6+\n\nThe `tarantool/smtp` module is for sending email via SMTP with\nthe [Tarantool](http://https://tarantool.org) application server.\n\nSince Tarantool already has facilities for setting up Internet servers,\nand can take advantage of the [libcurl](http://https://curl.haxx.se/libcurl)\nlibrary for data transfer via URLs, `tarantool/smtp` simply builds on\nfunctionality that is in the main package.\n\nWith Tarantool and `tarantool/smtp`, developers have the routines for\nsetting up an email client, and the facilities for testing locally before\ndeploying to the Internet. This may be particularly interesting for developers\nwho use Tarantool's database, Lua application server, and HTTP features.\n\n## Contents\n\n* [How to install](#how-to-install)\n* [The client request function](#the-client-request-function)\n* [The server](#the-server)\n* [OK, run it](#ok-run-it)\n* [Contacts](#contacts)\n\n## How to install\n\nYou will need:\n\n* Tarantool 1.6+ with header files (`tarantool` and `tarantool-dev` modules)\n* `curl`\n* an operating system with developer tools including `cmake`, a C compiler,\n  `git` and Lua\n\nYou have two ways to install `tarantool/smtp`:\n\n1. The first way is to\n   [use the Tarantool Lua rocks repository](https://tarantool.org/en/doc/1.7/book/app_server/installing_module.html#installing-a-module-from-a-repository).\n\n   With Tarantool 1.7.4+, say:\n\n   ```sh\n   tarantoolctl rocks install smtp\n   ```\n\n   With earlier Tarantool versions, set up Lua rocks and then say:\n\n   ```sh\n   luarocks --local install smtp\n   ```\n\n2. The second way is to clone from https://github.com/tarantool/smtp, build,\n   and use the produced library:\n\n   ```bash\n   git clone https://github.com/tarantool/smtp.git smtp\n   cd smtp\n   cmake . \u0026\u0026 make\n   # and use the library as shown in \"Ok, run it\" section below\n   ```\n\nWhichever way you choose, it is still a good idea to look at the files in the\ngithub.com/tarantool/smtp repository.\nThere are example files and commented test files, which will aid you in\nunderstanding how `tarantool/smtp` was put together.\n\n[Back to contents](#contents)\n\n## The client request function\n\nThere is only one function in the smtp module: `client()`.\n\nIt is a tool for handling the job of communicating with the server\nat a high level.\n\nFormat: *client(url, from, to, body [, options])*\n\nThe parameters are:\n\n`url` -- type = string; value = the URL of the SMTP, including the protocol.\nExample: `\"smtp://127.0.0.1:34324\"`.\n\n`from` -- type = string; value = the name of the sender as it would\nappear in an email 'From:' line.\nExample: `\"sender@tarantool.org\"`.\n\n`to` -- type = string; value = the name of the recipients as they would\nappear in an email 'To:' line.\nThere can be more than one recipient, defined as an array.\nExample: {\"receiver_1@tarantool.org\", \"receiver_2@tarantool.org\"}.\n\n`body` -- type = string; value = the contents of the message.\nExample: `\"Test Message\"`.\n\n`options` -- type = table; value = one or more of the following:\n\n* `cc` -- a string or a list to send email copy\n* `bcc` -- a string or a list to send a hidden copy\n* `subject` -- a subject for the email\n* `headers` -- a list of headers (say,\n   `{'Message-id: \u003c1567551362.79420629@example.org\u003e', ...}`)\n* `content_type` (string) -- set a content type (part of a Content-Type header,\n  defaults to 'text/plain')\n* `charset` (string) -- set a charset (part of a Content-Type header, defaults\n  to 'UTF-8')\n* `ca_path` -- path to an ssl certificate directory\n* `ca_file` (string) -- path to file containing\n  [certificates for verifying the peer](http://curl.haxx.se/libcurl/c/CURLOPT_CAINFO.html)\n* `ca_path` (string) -- path to directory containing certificates for\n  verifying the peer\n* `verify_host` (boolean) -- whether to\n  [verify certificate names](http://curl.haxx.se/libcurl/c/CURLOPT_CAINFO.html)\n* `verify_peer` (boolean) -- whether to verify\n  [the peer's SSL certificate](http://curl.haxx.se/libcurl/c/CURLOPT_SSL_VERIFYPEER.html)\n* `ssl_cert` (string) -- path to\n  [SSL client certificate](http://curl.haxx.se/libcurl/c/CURLOPT_SSLCERT.html)\n* `ssl_key` (string) -- path to\n  [private key for TLS and/or SSL client certificate](http://curl.haxx.se/libcurl/c/CURLOPT_SSLKEY.html)\n* `use_ssl` -- request using SSL/TLS (1 - preferably, 3 - mandatory)\n* `timeout` (number) -- number of seconds to wait for the `libcurl` API\n* `verbose` (boolean) -- whether `libcurl` verbose mode is enabled\n* `username` (string) -- a username for server authorization\n* `password` (string) -- a password for server authorization\n* `attachments` (table) -- a table (array) with attachments data\n  * `body` (any) attachment body contents\n  * `content_type` (string) -- set a content type (part of a Content-Type header,\n  defaults to 'text/plain')\n  * `charset` (string) -- set a charset (part of a Content-Type header, defaults\n  to 'UTF-8')\n  * `filename` (string) -- a string with filename will be shown in e-mail\n  * `base64_encode` (boolean) -- a boolean to base64 encode attachment content or not, default is true\n\nExample: `{timeout = 2}`\n\nExample of a complete request:\n\n```lua\nresponse =\nclient:request(\"smtp://127.0.0.1:34324\",`\"sender@tarantool.org\"`,`\"receiver@tarantool.org\"`,\"Test\nMessage\",{timeout=2})\n```\n\nThe response to the request will be a table containing a status (number)\nand a reason (string).\nExample: `{status: 250, reason: Ok}`\n(The standard status code 250 means the request was executed.)\n\nExample of a complete request with attachments:\n\n```lua\nresponse =\nclient:request(\n  \"smtp://127.0.0.1:34324\",\n  \"sender@tarantool.org\",\n  \"receiver@tarantool.org\",\n  \"Test Message\",\n  {\n    timeout=2,\n    attachments = {\n      {\n          body = json.encode('{\"key1\":\"value1\"}'),\n          content_type = 'application/json',\n          charset = 'UTF-8',\n          filename = 'json.json',\n          base64_encode = true\n      },\n      {\n          body = 'Test example',\n          content_type = 'text/plain',\n          filename = 'example.txt',\n          base64_encode = false\n      }\n    }\n  })\n```\n\n[Back to contents](#contents)\n\n## The server\n\nAn SMTP server does not come with `tarantool/smtp`, but `tarantool/smtp` does\nsupply example code of an SMTP server that can be run on Tarantool --\n[tmtp.test.lua](https://github.com/tarantool/smtp/blob/master/test/smtp.test.lua).\nWe will use some of the code from this example to show that the request function\nworks correctly.\n\nBefore simply presenting the code and saying \"OK, run it\", we should explain\nwhat it is supposed to handle.\n\nTarantool has a module named\n[socket](https://tarantool.org/doc/1.7/reference/reference_lua/socket.html)\nwhich contains a `tcp_server()` function.\nIt is possible to make the TCP server run in the background as a\n[fiber](https://tarantool.org/doc/1.7/reference/reference_lua/fiber.html).\nAs is common with client/server action, the example code has a loop that watches\nfor incoming messages and processes them. In this case, it is processing\naccording to the standard expected format that goes to an SMTP server, such as\n\"EHLO\", \"RCPT FROM\", \"RCPT TO\", and \"DATA\", which are all\n[Simple Mail Transfer Protocol](https://https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol)\ncommands. When it encounters \"DATA\", it starts another loop to get all the lines\nof the message body.\n\nTo make the example simple, it is done on the local host without troubling to\ncheck CA certificates or passwords. The idea is not to compete with Internet\ngiants like Mail.Ru, but to prove `tarantool/smtp`'s request function calls work\nquickly.\n\n[Back to contents](#contents)\n\n## OK, run it\n\nStart Tarantool, run as a console:\n\n```bash\ntarantool\n```\n\nIf you cloned and built the library from source, add the library path to\n`package.cpath`, for example:\n\n```lua\n-- for Ubuntu\npackage.cpath = package.cpath .. './smtp/?.so;'\n-- for Mac OS\npackage.cpath = package.cpath .. './smtp/?.dylib;'\n```\n\nExecute these requests:\n\n```lua\n-- STARTUP\n\nbox.cfg{}\n\nfiber = require('fiber')\nsocket = require('socket')\nmails = fiber.channel(100)\n```\n\n```lua\n-- SERVER CODE\n\nfunction smtp_h(s)\n     s:write('220 localhost ESMTP Tarantool\\r\\n')\n     local l\n     local mail = {rcpt = {}}\n     while true do\n         l = s:read('\\r\\n')\nprint(l)\n         if l:find('EHLO') then\nprint(' EHLO')\n             s:write('250-localhost Hello localhost.lan [127.0.0.1]\\r\\n')\n             s:write('250-SIZE 52428800\\r\\n')\n             s:write('250-8BITMIME\\r\\n')\n             s:write('250-PIPELINING\\r\\n')\n             s:write('250-CHUNKING\\r\\n')\n             s:write('250-PRDR\\r\\n')\n             s:write('250 HELP\\r\\n')\n         elseif l:find('MAIL FROM:') then\nprint(' MAIL FROM')\n             mail.from = l:sub(11):sub(1, -3)\n             s:write('250 OK\\r\\n')\n         elseif l:find('RCPT TO:') then\nprint(' RCPT TO')\n             mail.rcpt[#mail.rcpt + 1] = l:sub(9):sub(1, -3)\n             s:write('250 OK\\r\\n')\n         elseif l == 'DATA\\r\\n' then\nprint(' DATA')\n             s:write('354 Enter message, ending with \".\" on a line by itself\\r\\n')\n             while true do\n                 local l = s:read('\\r\\n')\nprint(' DATA: ' .. l)\n                 if l == '.\\r\\n' then\n                     break\n                 end\n                 mail.text = (mail.text or '') .. l\n             end\n             mails:put(mail)\n             mail = {rcpt = {}}\n             s:write('250 OK OK OK\\r\\n')\n         elseif l:find('QUIT') then\nprint(' QUIT')\n             return\n         elseif l ~= nil then\nprint(' not implemented')\n             s:write('502 Not implemented')\n         else\n             return\n         end\n     end\nend\n\nserver = socket.tcp_server('127.0.0.1', 0, smtp_h)\naddr = 'smtp://127.0.0.1:' .. server:name().port\n```\n\n```lua\n-- TARANTOOL/SMTP REQUEST CODE\n\nclient = require('smtp').new()\n\nresponse = client:request(addr, 'sender@tarantool.org',\n     'receiver@tarantool.org',\n     'mail.body')\n```\n\nNow pause and look at what the server's `print()` requests did: they should show\nthat the server received EHLO, MAIL FROM, RCPT TO and DATA.\n\nNow look at the response. It should look like this:\n\n```lua\ntarantool\u003e response\n---\n- status: 250\n   reason: Ok\n...\n```\n\nThis means the request has been sent and handled. (It does not mean that the\nrequest will pop up on the mailbox of `receiver@tarantool.org`, because this\nis done with a local test server, with none of the usual authorization options.)\n\nOnce you see that the response is 'Ok', you can switch from being a sender to\nbeing a receiver. Say:\n\n```lua\nmails:get()\n```\n\nAnd now the response should look like this:\n\n```lua\ntarantool\u003e mails.get()\n---\n- from: \u003csender@tarantool.org\u003e\n   rcpt:\n   - \u003creceiver@tarantool.org\u003e\n   text: \"TO: receiver@tarantool.org\\r\\nCC: \\r\\n\\r\\nmail.body\\r\\n\"\n...\n\n```\n\nIf that is what you see, then you have successfully installed `tarantool/smtp`\nand successfully executed a request function that sent an email to an SMTP\nserver, and confirmed it by getting the email back to yourself.\n\n[Back to contents](#contents)\n\n## Contacts\n\nThe Tarantool organization at this time includes dozens of developers and\nsupport staffers, so you will have no trouble contacting and getting a response\nfrom an expert.\n\nIf you see what you think is a bug, or if you have a feature request, go to\n[github.com/tarantool/smtp/issues](https://github.com/tarantool/smtp/issues)\nand fill out a description.\n\nIf you want to hear more about Tarantool, go to tarantool.org and look for new\nannouncements about this and other modules.\n\n[Back to contents](#contents)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftarantool%2Fsmtp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftarantool%2Fsmtp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftarantool%2Fsmtp/lists"}