Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Add std/smtp module #8413

Closed
wants to merge 6 commits into from
Closed

WIP: Add std/smtp module #8413

wants to merge 6 commits into from

Conversation

uki00a
Copy link
Contributor

@uki00a uki00a commented Nov 17, 2020

Towards #7906.

Summary

Usage

import { sendMail } from "https://deno.land/std/smtp/mod.ts";

await sendMail({
  addr,
  from: "from@example.com",
  to: ["to@example.com"],
  msg
});

Changes

  • Add std/smtp module.
  • Move TextProtoReader class from std/textproto/mod.ts to std/textproto/reader.ts and re-export it from std/textproto/mod.ts.
  • Add TextProtoWriter class (std/textproto/writer.ts)
  • Add TextProtoConn class (std/textproto/conn.ts)

Question

This PR is a bit more complex 😢 Should I split this PR into multiple PRs?

TODO

  • Add more tests
  • Cleanup code
  • Fix implementation of cram-md5 (which is currently broken)
  • Add README.md

@uki00a uki00a changed the title WIP: add std/smtp module WIP: Add std/smtp module Nov 17, 2020
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
*/
export function validateLine(line: string): void {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe move into _address_validation.ts to remove the generically named helpers.ts?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_util.ts would be more consistent. These are private, I wouldn't worry about a generic _util module per-directory.

* See func Dial for a description of the hostport parameter, and host
* and port results.
*/
export function splitHostPort(hostport: string): [string, number] {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe move into _address_parameter_extrator.ts to remove the generically named helpers.ts?

export function splitHostPort(hostport: string): [string, number] {
const missingPort = "missing port in address";
const tooManyColons = "too many colons in address";
function addrErr(addr: string, why: string): AddrError {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid contraction and use addressError as the name?

let j = 0, k = 0;

// The port starts after the last colon.
const i = hostport.lastIndexOf(":");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit pick: Not a fan of variable name with single letter, how about indexOfLastColon

function addrErr(addr: string, why: string): AddrError {
return new AddrError(why, addr);
}
let j = 0, k = 0;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit pick: Not a fan or single letter variables

let code2: number;
let moreMessage: string;
[code2, continued, moreMessage] = await parseCodeLine(line, 0);
if (code2 !== code) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code2 and code are hard to understand as variable names? Can these be named better?

continued = true;
continue;
}
message += "\n" + moreMessage;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a named constant for \n?

skipSpace(l: Uint8Array): number {
let n = 0;
for (let i = 0; i < l.length; i++) {
if (l[i] === charCode(" ") || l[i] === charCode("\t")) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, would it be more reabable to name named constants for space and tab?

}

function parseCodeLine(line: string, expectCode: number): CodeLine {
if (line.length < 4 || (line[3] !== " " && line[3] !== "-")) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few magic numbers here. Named constant for 3 and 4 would reveal the position significance?

break;
case WRITE_STATE_CR:
this.#state = WRITE_STATE_DATA;
if (c === charCode("\n")) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More uses of the \n and \r. As these are also reference in the other files can they share a enum to improve readability

Comment on lines +86 to +90
class AddrError extends Error {
constructor(why: string, readonly addr: string) {
super(why);
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be exported if users see it. Does this class need to exist, though?

@kitsonk
Copy link
Contributor

kitsonk commented Nov 18, 2020

Please not a tag of a suggestion as the original issue is tagged does not mean there is agreement to add something. It is simply a request. We should really resolve if it is suitable in the issue before PRs are raised.

I personally believe we shouldn't add something like this to std. It is a great opportunity for it to be a community module.

@ry
Copy link
Member

ry commented Nov 19, 2020

@uki00a This looks pretty good! But because of the size - it's going to be difficult for us to review this properly.

I would feel much more comfortable merging this into std if it first existed in deno.land/x people were using it.

How does this compare to? https://deno.land/x/smtp@v0.6.0

@uki00a
Copy link
Contributor Author

uki00a commented Nov 19, 2020

@ry From my personal point of view, I compared each module:

std/smtp

  • Provides both high-level (sendMail()) and low-level (SmtpClient#mail(), SmtpClient#rcpt(), SmtpClient#data(), etc.) APIs for sending mails.

x/smtp

  • Published since 2019/06 (so some users may already be using this module).
  • Provides high-level API (SmtpClient#send()) for sending emails.
  • The author, @manyuanrong, has made significant contributions to the Deno community (e.g. deno_mysql and deno_mongo), so I consider this module to be reliable as well.

My personal thoughts

  • x/smtp looks good to me 👍
  • I think it may be confusing that SMTP modules exist in both /std and /x.

@stale
Copy link

stale bot commented Jan 21, 2021

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Jan 21, 2021
@bartlomieju
Copy link
Member

@uki00a looks like this PR is still not ready, so we won't land this PR before standard library migration to a separate repository (#9029 (comment)).

I'm still very much interested in discussing these changes on upcoming meetings and potentially landing the PR.

@PodaruDragos
Copy link

PodaruDragos commented Jan 25, 2021

this would be such a good addition to std. i know people disagree with the fact that the smtp module should be part of std, but look at node and nodemailer and after then maybe reconsider :)

@bartlomieju
Copy link
Member

Deno standard library was moved to denoland/deno_std, please reopen your PR there.

@bartlomieju bartlomieju closed this Feb 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants