Nodemailer envois de mail par un bouton

Bonjour,

Je viens de configurer un fichier mail.js avec tout les infos dedans quand je fais la commande node mail.js dans le terminal j’ai bien le mail qui part par contre comment je peux l’intégrer dans un bouton pour que le mail parte ?

j’ai pas trouve de solution donc me voila :-)

si je comprend bien ,

  • mail.js represente un service d’envoi de mail côté serveur (Node.js)
  • Tu l’as testé via la CLI node
  • maintenant tu veux, côté frontend qu’au click sur un bouton, ca déclenche le service
    C’est ca ?

Bonjour non j’ai pas tester avec CLI node et oui c’est parfaitement ça au onclick j’aimerais appeler mon fichier mail.js pour envoyé le mail comme quand je fais node mail.js

Bonjour @VincentDev83,

Le fait que tu te poses cette question me laisse penser que tes connaissances actuelles entre un lien possible entre Node.js en tant qu’outil de développement de site web (ce dont tu as besoin ?) et Node.js en tant qu’outil de création de service web (ton mail.js actuelle).

Je peux te proposer de faire tes armes avec le framework NodeAtlas qui est parfait pour ce type de profil : https://node-atlas.js.org/ (Bien entendu, si ce n’est pas le cas et/ou que tu as déjà une techno où gréffer un appel API et un rendu côté client, passe ton chemin).

Pour répondre à ta question, il faut que le déclenchement de l’envoi de ton email soit piloter par une URL atteignable.

Imaginons que tu créer une url du type /send-email/. Tu vas pouvoir accéder à cette URL en faisant une request dessus avec la méthode HTTP POST qui contiendra tous les éléments nécessaires pour remplir l’email.

Pour accéder à cette URL tu devras faire appel (au clique de ton bouton) à la fonction JavaScript fetch (Utilisation de fetch : https://blog.lesieur.name/vanilla-js-france/#post) dans la mesure où, admettons, tu ne supportes que les navigateurs récent : https://caniuse.com/#feat=fetch.

Derrière l’URL /send-email/, le contenu de ton fichier mail.js (ou un fichier y faisant appel) sera exécuté et te permettra d’envoyer un email comme tu le souhaites. En fonction de la response que cette URL renverra à ton client (celui qui a exécuté fetch), tu serra ensuite capable côté client (l’interface sur laquelle tu avais utilisé ton bouton d’envoi d’email) de savoir ce qu’il faudra faire ensuite (ex. informer l’utilisateur que tout c’est bien passé ou justement que l’email n’a pas pu partir).

Cette réponse est assez générale, je sais, mais c’est souvent le cas quand une réponse répond à une question générale ;)

En espérant t’avoir aiguillé. Peut-être que je ferrais un petit projet exemple à partir de ce que j’ai sous la main.

tu as fait
$ node main.js

donc tu as bel et bien utilisé la CLI node (la ligne de commande) ;-)

Pour déclencher le service mail du backend depuis une interface frontend
il faut que tu exposes le service mail sous la forme d’un web service Rest

Pour mettre ca en place en 2 minutes top chrono en mode prototype : Restify :

En bref, dans les grandes lignes il te faut :

  • un serveur web qui écoute sur une adresse (ex: localhost) et un port (8080 par ex)
  • une route qui permet d’atteindre ce controller + params d’entrée
  • un controller qui receptionne ta requete venant du frontend
  • …et qui déclenche le service mail

C’est ce que décrit la doc de Restify

Autre chose :
si tu veux à la fois que le frontend ET le backend soitent disponibles sur la même adresse:port
(et ainsi t’éviter certaines contraintes inutiles à ce stade)
il faut que Restify, en plus de fournir un web service, puisse aussi fournir du contenu statique (autrement dit ton frontend)

  • 1 route (ex: “/”) pour ton frontend (qui fournit que du HTML)
  • 1 route préfixée (ex: “/api/mailto/”) pour ton backend

Restify et contenu statique

1 J'aime

Voici un exemple complet que tu pourras adapter au contenu de mail.js qui répond à ta question avec NodeAtlas (équivalent de restify proposé par @tagadapps). Tu peux également l’adapter en utilisant des routes de Express.js par exemple ou en utilisant ton framework favori (ou même du Vanilla“Node”.js ;) )

Dossier Github testable, toutes les instructions sont dans le README.md
https://github.com/Haeresis/HumanCoders/tree/master/nodemailer-envois-de-mail-par-un-bouton/node-atlas-version/

Basiquement nous avons l’URL / qui fait appelle à la vue index.htm dont voici le contenu :

<!DOCTYPE html>
<html>
<head>
	<title>Nodemailer envois de mail par un bouton</title>
	<style type="text/css">
		.send-email__processing,
		.send-email__success,
		.send-email__failure,
		.send-email.is-processing .send-email__init,
		.send-email.is-success .send-email__init,
		.send-email.is-failure .send-email__init {
			display: none;
		}

		.send-email.is-processing .send-email__processing,
		.send-email.is-success .send-email__success,
		.send-email.is-failure .send-email__failure {
			display: block;
		}
	</style>
</head>
<body>
	<section class="send-email">
		<div class="send-email__init">
			<p>De : <input class="send-email__from" type="text" name="from"></p>
			<p>À : <input class="send-email__to" type="text" name="to"></p>
			<p>Sujet: <input class="send-email__subject" type="text" name="subject"></p>
			<p>
				Contenu:<br>
				<textarea class="send-email__content" name="content"></textarea>
			</p>
			<button class="send-email__init-button">Envoyer un email</button>
		</div>
		<div class="send-email__processing">
			<p>Envoi en cours...</p>
		</div>
		<div class="send-email__success">
			<p>Votre email a correctement été envoyé!</p>
		</div>
		<div class="send-email__failure">
			<p>Votre email n'a pas été envoyé…</p>
		</div>
	</section>
	<script type="text/javascript">
		/* jslint node: true */
		var debug = true,
			button = document.getElementsByClassName('send-email__init-button')[0],
			sendEmail = document.getElementsByClassName('send-email')[0],
			sendEmailFrom = document.getElementsByClassName('send-email__from')[0],
			sendEmailTo = document.getElementsByClassName('send-email__to')[0],
			sendEmailSubject = document.getElementsByClassName('send-email__subject')[0],
			sendEmailContent = document.getElementsByClassName('send-email__content')[0];

		button.addEventListener('click', function () {
			var mailOptions = {
				to: sendEmailFrom.value,
				from: sendEmailTo.value,
				subject: sendEmailSubject.value,
				content: sendEmailContent.value
			};

			debug && console.log('debug', mailOptions);

			sendEmail.classList.add('is-processing');

			fetch('http://localhost:7749/send-email/', {
			    method: 'POST',
			    headers: {
					'Accept': 'application/json',
					'Content-Type': 'application/json'
				},
			    body: JSON.stringify(mailOptions)
			})
			.then(function(response) {
				response.text().then(function (data) {
					sendEmail.classList.remove('is-processing');
					if (data.success) {
						sendEmail.classList.add('is-success');
					} else {
						sendEmail.classList.add('is-failure');
					}
				});
			});
		});
	</script>
</body>
</html>

Qui via la méthode fetch sur le clique du bouton appelle l’URL /send-email/ qui fait appelle au contrôleur sendemail.js et à la vue json.htm

Voici le contenu du contrôleur en question :

/* jslint node: true */
exports.changeVariations = function (next, locals, request, response) {
	var debug = true,
		NA = this,
		nodemailer = NA.modules.nodemailer;
		transporter = nodemailer.createTransport('smtps://' + NA.webconfig._smtpLoginAuth + ':' + NA.webconfig._smtpPasswordAuth + '@' + NA.webconfig._smtpProviderAuth),
		mailOptions = {
			from: request.body.from,
			to: request.body.to,
			subject: request.body.subject,
			text: request.body.content
		};

	debug && console.log('debug', mailOptions);

	transporter.sendMail(mailOptions, function (error) {
		if (error) {

			// FAILLURE
			response.statusCode = 503;
			locals.specific = { success: false, error: error };
		} else {

			// SUCCESS
			response.statusCode = 200;
			locals.specific = { success: true };
		}

		next();
	});
};

Qui renvoi au client le fait que l’email est correctement parti ou non (dans notre cas une erreur car les variables d’accès au SMTP sont vide, voir plus bas).

Le détail des deux routes nécessaires (l’appelant front-end et l’endpoint REST) sont décrit dans le webconfig.json (ainsi que le port et l’URL déjà mentionné par @tagadapps ).

{
	"httpPort": 7749,
	"controller": "common.js",
	"routes": [{
		"url": "/",
		"view": "index.htm"
	}, {
		"url": "/send-email/",
		"get": false,
		"post": true,
		"view": "json.htm",
		"controller": "sendemail.js",
		"mimeType": "application/json"
	}],
	"_smtpLoginAuth": "",
	"_smtpPasswordAuth": "",
	"_smtpProviderAuth": ""
}

C’est en fonction de cette réponse que nous choisissons de quelle manière nous informons ensuite l’utilisateur final (voir la partie JavaScript de index.htm).


Du coup je me suis créer un petit projet GitHub HumanCoders pour faire plus de réponse de ce type à l’avenir ;)

Petite précision je suis sous react.

@Haeresis ca fait peut etre beaucoup d’un coup non ?

Un simple example avec un Express-like quand on est débutant c’est plus digeste.

@VincentDev83 React, jQuery, Angular, Vanilla, ca importe peu
sous React ben tu vas sans doute attacher le “click” de ton bouton avec une fonction dans le controller de ton component, non ?
Et pour déclencher l’envoi de mail effectivement tu peux passer par Fetch (dixit @Haeresis) pour appeler l’URL de ton service :

@tagadapps

De mon point de vu, compte tenu des informations suivantes que j’avais à ma disposition et/ou extrapolée au moment de ma réponse :
— Niveau « extrapolé » de la personne en face : « Le fait que tu te poses cette question [laisse penser que vous avez] peu de connaissance [en] Node.js en tant qu’outil de développement de site web […]. »
— Code sous la main dans mes projets : « Peut-être que je ferrais un petit projet exemple à partir de ce que j’ai sous la main ».
alors :

« Ça fait peut etre beaucoup d’un coup non ? »
La partie importante à mon sens sont les fichiers exposés dans ma réponse. Ça cache le lien client-server potentiellement déjà gérer par un outil (cas où @VincentDev83 a déjà un framework) ou ça lui permet d’en découvrir un adapter pour permettre au débutant d’aprendre Node.js (cas où il n’en a pas). J’imagine que c’est ce second cas (devoir prendre en main l’outil) que tu estimes être « etre beaucoup d’un coup » :D

« Un simple exemple avec un Express-like quand on est débutant c’est plus digeste. »
C’est ici que je ne te rejoins pas, probablement parce que nous n’avons pas la même définition derrière le mot « débutant » dans ce contexte précis. De mon côté, connaissant aussi bien Express.js que NodeAtlas, je pense qu’il est plus simple pour un « débutant Node.js » de parvenir à quelque chose avec NodeAtlas, qu’avec Express.js. Il sera par contre plus simple pour un initié à Node.js de bien comprendre là « totalité » des étapes de la chaine à partir de Express.js (qui les exposes toutes puisque développé à la main, c.-à-d. que la totalité du code de l’exemple serait auto-explicatif, si tentait que la personne à déjà des connaissances en Node.js). Dans mon hypothèse initiale, celle d’un échange avec un débutant, devoir découvrir NodeAtlas plutôt que Express.js (donc qu’aucun n’était connu à l’avance) me semblait une approche réellement plus simple (et je n’ai pas dit nécessairement moins longue).

J’espère que cela clarifie mon intention initiale :)

Mais en réalité, la vrai réponse a ces questions ne pourrait être apporté que part un @VincentDev83 qui se dédoublerait et qui essairai les deux chemins :)

Par contre, à l’affirmation : « Un simple example avec un Express-like quand on est débutant fait également l’affaire. », je réponds « Absoluement ».

Du coup ça m’a donner envie de faire une version Express.js. J’ai un peu de temps devant moi, je me tate :p

@VincentDev83

Est-ce que nos réponses répondent à ta question ?

En relisant le message de @tagadapps, je me suis aperçu qu’il ne parlait pas nécessairement de Express.js mais de « Express-like » aussi en voici un exemple en Vanilla JS plus « digeste » :p ) :

Dossier Github testable, toutes les instructions sont dans le README.md
https://github.com/Haeresis/HumanCoders/tree/master/nodemailer-envois-de-mail-par-un-bouton/node-js-version/

Basiquement nous avons l’URL / qui fait appelle à la vue index.htm dont voici le contenu :

<!DOCTYPE html>
<html>
<head>
	<title>Nodemailer envois de mail par un bouton</title>
	<style type="text/css">
		.send-email__processing,
		.send-email__success,
		.send-email__failure,
		.send-email.is-processing .send-email__init,
		.send-email.is-success .send-email__init,
		.send-email.is-failure .send-email__init {
			display: none;
		}

		.send-email.is-processing .send-email__processing,
		.send-email.is-success .send-email__success,
		.send-email.is-failure .send-email__failure {
			display: block;
		}
	</style>
</head>
<body>
	<section class="send-email">
		<div class="send-email__init">
			<p>De : <input class="send-email__from" type="text" name="from"></p>
			<p>À : <input class="send-email__to" type="text" name="to"></p>
			<p>Sujet: <input class="send-email__subject" type="text" name="subject"></p>
			<p>
				Contenu:<br>
				<textarea class="send-email__content" name="content"></textarea>
			</p>
			<button class="send-email__init-button">Envoyer un email</button>
		</div>
		<div class="send-email__processing">
			<p>Envoi en cours...</p>
		</div>
		<div class="send-email__success">
			<p>Votre email a correctement été envoyé!</p>
		</div>
		<div class="send-email__failure">
			<p>Votre email n'a pas été envoyé…</p>
		</div>
	</section>
	<script type="text/javascript">
		/* jslint browser: true */
		var debug = true,
			button = document.getElementsByClassName('send-email__init-button')[0],
			sendEmail = document.getElementsByClassName('send-email')[0],
			sendEmailFrom = document.getElementsByClassName('send-email__from')[0],
			sendEmailTo = document.getElementsByClassName('send-email__to')[0],
			sendEmailSubject = document.getElementsByClassName('send-email__subject')[0],
			sendEmailContent = document.getElementsByClassName('send-email__content')[0];

		button.addEventListener('click', function () {
			var mailOptions = {
				to: sendEmailFrom.value,
				from: sendEmailTo.value,
				subject: sendEmailSubject.value,
				content: sendEmailContent.value
			};

			debug && console.log('debug', mailOptions);

			sendEmail.classList.add('is-processing');

			fetch('http://localhost:7749/send-email/', {
			    method: 'POST',
			    headers: {
					'Accept': 'application/json',
					'Content-Type': 'application/json'
				},
			    body: JSON.stringify(mailOptions)
			})
			.then(function(response) {
				response.text().then(function (data) {
					sendEmail.classList.remove('is-processing');
					if (data.success) {
						sendEmail.classList.add('is-success');
					} else {
						sendEmail.classList.add('is-failure');
					}
				});
			});
		});
	</script>
</body>
</html>

Qui via la méthode fetch sur le clique du bouton appelle l’URL /send-email/ qui fait appelle au contrôleur sendemail.js

Voici le contenu du contrôleur en question :

/* jslint node: true */
exports.main = function (next, request, response) {
	var debug = true,
		nodemailer = require('nodemailer'),
		smtpLoginAuth = "",
		smtpPasswordAuth = "",
		smtpProviderAuth = "",
		transporter = nodemailer.createTransport('smtps://' + smtpLoginAuth + ':' + smtpPasswordAuth + '@' + smtpProviderAuth);
		body = [];

	request.on('data', function (chunk) {
		body.push(chunk);
	}).on('end', function () {
		var mailOptions;

		body = JSON.parse(Buffer.concat(body).toString());	
		mailOptions = {
			from: body.from,
			to: body.to,
			subject: body.subject,
			text: body.content
		};

		debug && console.log('debug', mailOptions);

		transporter.sendMail(mailOptions, function (error) {
			if (error) {

				// FAILLURE
				response.writeHead(503, {
					"Content-Type": "application/json; charset=utf-8"
				});
				next({ success: false, error: error });
			} else {

				// SUCCESS
				response.writeHead(200, {
					"Content-Type": "application/json; charset=utf-8"
				});
				response.statusCode = 200;
				next({ success: true });
			}
		});
	});
};

Qui renvoi au client le fait que l’email est correctement parti ou non (dans notre cas une erreur car les variables d’accès au SMTP sont vide, voir plus bas).

Le détail des appels nécessaires (l’appelant front-end et l’endpoint REST) sont développé dans le fichier server.js (ainsi que le port et l’URL déjà mentionné par @tagadapps ).

/* jslint node: true */
var http = require("http"),
	fs = require("fs"),
	httpPort = 7749,
	httpServer;

httpServer = http.createServer(function (request, response) {
	var router = {
		"/": {
			view: "index.htm",
			controller: false
		},
		"/send-email/": {
			view: false,
			controller: "sendemail.js"
		}
	},
	view = router[request.url].view,
	controller = router[request.url].controller,
	statusCode = (router[request.url].view) ? 200 : 404;

	if (view) {	
		fs.readFile('./views/' + view, "utf-8", function (err, content) {
			if (err) { 
				console.log("We cannot open " + view + " view file.");
			}

			response.writeHead(statusCode, {
				"Content-Type": "text/html; charset=utf-8"
			});

			response.end(content);
		});
	}

	if (controller) {
		require('./controllers/' + controller).main(function (content) {
			response.end(JSON.stringify(content, null, '    '));
		}, request, response);
	}
});

httpServer.listen(httpPort, function () {
  console.log("Server listening on: http://localhost:%s", httpPort);
});

C’est en fonction de cette réponse que nous choisissons de quelle manière nous informons ensuite l’utilisateur final (voir la partie JavaScript de index.htm).


Merci à @tagadapps pour l’exercice super intéressant !

J’espère qu’avec tout ça @VincentDev83, tu trouverras ton bonheur :)

Je ne me suis pas étendu sur la partie frontend, il l’a deja.

L’exemple fourni dans le README de Restify est assez limpide et peu de lignes de code à comprendre.

  • Restify est basé sur Express et le simplifie.
  • Express est le serveur web le plus répandu dans le monde Node (mainstream, plein de docs).
  • Je l’ai utilisé à mes débuts pour me faire la main sur les API Rest (et conteu statique) en Node

Je le recommande au regard de ces arguments.

1 J'aime

Allez, je vais faire un petit exercice de Zététique et passer pour un relou :) mais ça me démange XD.

Lorsque nous avons tout deux répondu, nous n’avions pas l’information que le Front-end existait déjà en React. Ce n’est donc originalement pas pour cette raison que vous ne vous étiez pas étendu. On appelle cela de la Rationalisation (p-e le manque de temps, p-e que l’explication se suffisait à elle même, p-e la supposition de l’existence d’un front, etc.).

Après pour reprendre votre argumentaire :

  • NodeAtlas est basé sur Express et le simplifie.
  • Express est le serveur web le plus répandu dans le monde Node (mainstream, plein de docs).
  • Je l’ai utilisé à mes débuts pour me faire la main sur les API Rest (et conteu statique) en Node.

Le critère de différentiation reste donc subjectif dans ce cas de figure. Les réponses de ce thread me semble toutes aussi utiles.

On pourrait croire que ce message ne sert à rien mais je pense qu’il permet de recentrer le choix de la techno back sur les préférences du développeur plutôt que sur des points factuels équivalent dans les deux camps. Même si je sais qu’à cause de la réactance il est fort possible que ce message ne plaise pas (pour cela que je fais mon “relou”).

Il existe probablement des points factuels de différenciation pertinent, mais ils n’ont pas été fourni dans l’argumentaire présent. On pourrait les ajouter à postériori. On appellerait cela des explications ad hoc.

Et cela ne remet pas en cause l’idée subjective que Restify est un très bon choix ! “On peut avoir raison pour de mauvaises raisons” ;)

Ça ferra un mini exo de Zet pour @camilleroux :p

1 J'aime