Files
correos_api/src/mail/mail.service.ts
T
2025-06-27 20:09:46 -06:00

239 lines
6.0 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Injectable, UnauthorizedException } from '@nestjs/common';
import * as nodemailer from 'nodemailer';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Correo, Sistema, Status } from '../typeorm/entidades';
import { SistemaService } from 'src/sistema/sistema.service';
import { SendCorreoDto } from 'src/mail/dto/send-email.dto';
import { AuthService } from 'src/auth/auth.service';
import { decrypt } from '../crypto/crypto.util';
@Injectable()
export class MailService {
constructor(
private readonly sistemaService: SistemaService,
private readonly authService: AuthService,
@InjectRepository(Correo) private readonly correoRepository: Repository<Correo>,
@InjectRepository(Status) private readonly statusRepository: Repository<Status>,
@InjectRepository(Sistema) private readonly sistemaRepositosistemaRepositoryry: Repository<Sistema>
) {
/* this.transporter = nodemailer.createTransport({
host: 'smtp-relay.gmail.com',
port: 587,
secure: false,
requireTLS: true,
auth: {
user: process.env.USER_GMAIL,
pass: process.env.PASS_GMAIL,
},
}); */
/*
this.transporter = nodemailer.createTransport({
host: 'smtp.gmail.com', // o smtprelay.gmail.com (ver punto 2)
port: 587,
secure: false,
requireTLS: true, // TLS STARTTLS
auth: { user: process.env.USER_GMAIL, pass: process.env.PASS_GMAIL },
pool: true, // <‑‑ activa reuse
maxConnections: 1, // una sola conexión viva
maxMessages: 100, // reabrir después de 100 envíos
rateDelta: 2000, // ventana 1 s
rateLimit: 1 // máx. 5 mensajes/seg
});
*/
/*
this.transporter = nodemailer.createTransport({
host: 'localhost',
port: 1025,
ignoreTLS: true,
});
*/
}
async findAllBySistema(TOKEN:string,nombreSistema:string){
if (!TOKEN) {
throw new UnauthorizedException('Header "Password" es requerido');
}
const sistem=await this.sistemaService.acceso(TOKEN)
if(!sistem){
throw new UnauthorizedException('Password incorrecto');
}
const result= await this.correoRepository.find({where:{
id_sistema:{nombre_sistema:nombreSistema}
},
relations: {
id_sistema: true,
id_status: true,
},}
)
return result
}
async sendMail(sendEmail:SendCorreoDto,token:string) {
let payload
payload = await this.authService.verificarToken(token);
if (!payload || !payload.nombre) {
throw new UnauthorizedException('Token inválido o incompleto');
}
const sistem= await this.sistemaService.findByNombre(payload.nombre)
if(!sistem){
throw new UnauthorizedException('sistema No encontrado');
}
const decryptedPassword = decrypt(
sistem.email_password_encrypted,
sistem.email_password_iv
);
const decryptedToken = decrypt(
sistem.refreshToken_encrypted,
sistem.refreshToken_iv
);
const transporter = nodemailer.createTransport({
/* host: 'smtp.gmail.com', // o smtprelay.gmail.com (ver punto 2)
port: 587,
secure: false,
requireTLS: true, // TLS STARTTLS
auth: { user:sistem.email, pass:decryptedPassword},
pool: true, // <‑‑ activa reuse
maxConnections: 1, // una sola conexión viva
maxMessages: 100, // reabrir después de 100 envíos
rateDelta: 2000, // ventana 1 s
rateLimit: 1 // máx. 5 mensajes/seg
*/
service: 'gmail',
auth: {
type: 'OAuth2',
user: sistem.email,
clientId: sistem.clientId,
clientSecret: decryptedPassword,
refreshToken: decryptedToken,
//accessToken: sistem.accessToken, // opcional
},
pool: true,
maxConnections: 1,
maxMessages: 100,
rateDelta: 2000,
rateLimit: 1
});
console.log("estos son los archivos adjuntos en el service",sendEmail.adjuntos);
const mailOptions = {
from: sistem.email,
to:sendEmail.to,
subject:sendEmail.subject,
text: sendEmail.text,
html:sendEmail.html,
// OJO: nodemailer usa 'attachments', no 'adjuntos'
attachments: (sendEmail.adjuntos || []).map((adj) => {
// Asegúrate de no incluir 'data:image/png;base64,' en 'content'
let base64Clean = adj.content;
// Si viene con prefijo "data:image...", lo quitamos
if (base64Clean.startsWith('data:image/')) {
base64Clean = base64Clean.split('base64,')[1];
}
return {
filename: adj.filename || 'qr.png',
content: Buffer.from(base64Clean, adj.encoding || 'base64'),
cid: adj.cid || 'qrCode', // el mismo que uses en <img src="cid:..."/>
contentType: 'image/png' // recomendable para que sepa que es PNG
};
})
};
console.log(mailOptions);
let resMail = await transporter.sendMail(mailOptions);
if(!resMail) throw new Error("")
const statusTexto = resMail.accepted.length > 0 ? "Enviado" : "Fallido";
let status = await this.statusRepository.findOne({ where: { status: statusTexto } });
if (!status) {
status = this.statusRepository.create({ status: statusTexto });
await this.statusRepository.save(status);
}
const info= this.correoRepository.create({
id_status: status,
id_sistema: sistem,
fecha_recibido: sendEmail.fecha_recibido,
fecha_enviado: new Date(),
destinatario: sendEmail.to,
remitente: sistem.email,
});
if(!resMail){
throw new Error("fallo")
}
this.correoRepository.save(info);
return (statusTexto);
}
}