Buenas:
Quiero enviar un email en modo consola que supere los 255 caracteres tal como se hace en cualquier navegador.
¿Es posible hacerlo?
Aquí dejo un ejemplo con Ggail.
// Activar / desactivar Acceso de aplicaciones poco seguras en Google.
// https://myaccount.google.com/lesssecureapps
using System;
using System.IO;
using System.Net;
using System.Net.Mail;
using System.Text;
namespace Enviar_email_Consola_07
{
internal class Program
{
static void Main(string[] args)
{
#region Configuración ventana.
// Título de la ventana.
Console.Title = "Gestor correo electrónico";
// Tamaño de la ventana, x, y.
Console.SetWindowSize(80, 25);
// Color de fondo.
Console.BackgroundColor = ConsoleColor.Black;
// Color de las letras.
Console.ForegroundColor = ConsoleColor.Gray;
// Limpiar pantalla y dejarlo todo en color de fondo.
Console.Clear();
// Visible el cursor.
Console.CursorVisible = true;
#endregion
// Variables.
string usuario, contraseña, destinatario, asunto, mensaje;
// Título del programa.
Console.WriteLine("\t\t----------------------------------------");
Console.WriteLine("\t\t\tEnviar Correo Electrónico");
Console.WriteLine("\t\t----------------------------------------");
try
{
Console.WriteLine("\n");
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write("\t\tTu correo electrónico: ");
Console.ForegroundColor = ConsoleColor.Gray;
usuario = Console.ReadLine();
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write("\t\tIntroducir contraseña: ");
Console.ForegroundColor = ConsoleColor.Gray;
contraseña = LeerPassword();
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write("\t\tDestinatario: ");
Console.ForegroundColor = ConsoleColor.Gray;
destinatario = Console.ReadLine();
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write("\t\tAsunto: ");
Console.ForegroundColor = ConsoleColor.Gray;
asunto = Console.ReadLine();
Console.WriteLine();
//----------------------------------------------
byte[] bytes = new byte[2000]; // Nuevo tamanho máximo.
Stream inputStream = Console.OpenStandardInput(bytes.Length);
Console.SetIn(new StreamReader(inputStream));
//----------------------------------------------
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write("\t\tMensaje: ");
Console.ForegroundColor = ConsoleColor.Gray;
mensaje = Console.ReadLine();
Console.WriteLine();
MailMessage correo = new MailMessage(usuario, destinatario, asunto, mensaje);
SmtpClient servidor = new SmtpClient("smtp.gmail.com")
{
Port = 587
};
NetworkCredential credenciales = new NetworkCredential(usuario, contraseña);
servidor.Credentials = credenciales;
servidor.EnableSsl = true;
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("\t\tEnviando correo...");
servidor.Send(correo);
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("\t\tCorreo enviado satisfactoriamente.");
correo.Dispose();
Console.CursorVisible = false;
Console.ReadKey();
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("ERROR: \n");
Console.WriteLine("\t\t" + ex.Message);
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("\t\tNo se ha enviado el correo.");
Console.ReadKey();
}
}
// A la hora de introducir la contraseña, se sustituye por asterístos (*) en pantalla.
public static string LeerPassword()
{
ConsoleKeyInfo cki;
StringBuilder sb = new StringBuilder();
int contador = 0;
do
{
cki = Console.ReadKey(true);
if (cki.Key != ConsoleKey.Enter)
{
sb.Append(cki.KeyChar);
if (contador < 4)
{
Console.Write("*");
}
contador++;
}
else
{
break;
}
} while (true);
Console.WriteLine();
return sb.ToString();
}
}
}
Felices fiestas camaradas.
La función Console.ReadLine() tiene implícito ese límite de 256 caracteres (254 sin CarriageReturn + LineFeed). Ese es el límite del tamaño del búfer del que hace uso al adquirir el flujo de entrada estándar o std-in especificado en la función Console.OpenStandardInput.
Puedes incrementar dicho límite a 32.767(-2) caracteres de la siguiente manera:
Console.SetIn(new StreamReader(Console.OpenStandardInput(Int16.MaxValue), Console.InputEncoding, false, Int16.MaxValue));
O a 65.535(-2) caracteres si lo prefieres:
Console.SetIn(new StreamReader(Console.OpenStandardInput(UInt16.MaxValue), Console.InputEncoding, false, UInt16.MaxValue));
El límite máximo teórico es Int32.MaxValue ( Maximum length of byte[]? (https://stackoverflow.com/a/3944336/1248295) + <gcAllowVeryLargeObjects> element (https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/runtime/gcallowverylargeobjects-element?redirectedfrom=MSDN#remarks) ), pero llegar a esos extremos para este tipo de escenario lo veo totalmente innecesario.
La llamada al método Console.SetIn() puedes acomodarlo de forma reutilizable como en el siguiente ejemplo de clase, y simplemente llamar al método SetInBufferSize() cuando sea necesario:
Public NotInheritable Class ConsoleUtil
#Region " Constructors "
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Prevents a default instance of the <see cref="ConsoleUtil"/> class from being created.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
<DebuggerNonUserCode>
Private Sub New()
End Sub
#End Region
#Region " Private Members "
''' <summary>
''' The underlying standard input stream (stdin) used for <see cref="ConsoleUtil.SetInBufferSize"/> method.
''' </summary>
Private Shared stdIn As StreamReader
#End Region
#Region " Public Methods "
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Sets the buffer size of the standard input stream (std-in)
''' acquired from the <see cref="System.Console.OpenStandardInput"/> function.
''' <para></para>
''' So the <see cref="Console.ReadLine()"/> function can benefit from a larger buffer size.
''' <para></para>
''' Default buffer size is 256.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <param name="bufferSize">
''' Minimum value is: 256.
''' <para></para>
''' Note that the last two characters in the buffer are reserved for
''' <see cref="ControlChars.Cr"/> + <see cref="ControlChars.Lf"/>.
''' </param>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Public Shared Sub SetInBufferSize(bufferSize As Integer)
If bufferSize < 256 Then
Throw New ArgumentException(NameOf(bufferSize), message:="Value must be equal or greater than 256.")
End If
ConsoleUtil.stdIn?.Close()
ConsoleUtil.stdIn = New StreamReader(Console.OpenStandardInput(bufferSize), Console.InputEncoding, False, bufferSize)
Console.SetIn(ConsoleUtil.stdIn)
End Sub
#End Region
End Class
#End Region
Traducción a C#:
public sealed class ConsoleUtil {
#region Constructors
/// ----------------------------------------------------------------------------------------------------
/// <summary>
/// Prevents a default instance of the <see cref="ConsoleUtil"/> class from being created.
/// </summary>
/// ----------------------------------------------------------------------------------------------------
[DebuggerNonUserCode]
private ConsoleUtil() { }
#endregion
#region Private Members
/// <summary>
/// The underlying standard input stream (stdin) used for <see cref="ConsoleUtil.SetInputBufferSize"/> method.
/// </summary>
private static StreamReader stdIn;
#endregion
#region Public Methods
/// ----------------------------------------------------------------------------------------------------
/// <summary>
/// Sets the buffer size of the standard input stream (std-in)
/// acquired from the <see cref="System.Console.OpenStandardInput"/> function.
/// <para></para>
/// So the <see cref="Console.ReadLine()"/> function can benefit from a larger buffer size.
/// <para></para>
/// Default buffer size is 256.
/// </summary>
/// ----------------------------------------------------------------------------------------------------
/// <param name="bufferSize">
/// Minimum value is: 256.
/// <para></para>
/// Note that the last two characters in the buffer are reserved for
/// <see cref="ControlChars.Cr"/> + <see cref="ControlChars.Lf"/>.
/// </param>
/// ----------------------------------------------------------------------------------------------------
[DebuggerStepThrough]
public static void SetInBufferSize(int bufferSize) {
if (bufferSize < 256) {
throw new ArgumentException(nameof(bufferSize), message:"Value must be equal or greater than 256.");
}
ConsoleUtil.stdIn?.Close();
ConsoleUtil.stdIn = new StreamReader(Console.OpenStandardInput(bufferSize), Console.InputEncoding, false, bufferSize);
Console.SetIn(ConsoleUtil.stdIn);
}
#endregion
}
#endregion
----------------------
Como alternativa a lo de arriba, en caso de que prefieras no reemplazar el flujo de entrada estándar, puedes definir una función como esta de aquí abajo, que puedes añadir a la clase de arriba, para que sirva como reemplazo de la función Console.ReadLine().
VB.NET:
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Reads the next line of characters from the standard input stream.
''' <para></para>
''' This function attempts to be a improved replacement for <see cref="System.Console.ReadLine()"/> function.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <param name="bufferSize">
''' The character limit to read in the next line of characters from the standard input stream.
''' <para></para>
''' Minimum value is: 256.
''' <para></para>
''' Default value is: <see cref="Short.MaxValue"/> (32767).
''' <para></para>
''' Note that the last two characters in the buffer are reserved for
''' <see cref="ControlChars.Cr"/> + <see cref="ControlChars.Lf"/>.
''' </param>
''' ----------------------------------------------------------------------------------------------------
''' <returns>
''' The next line of characters from the input stream,
''' or <see langword="Nothing"/> if no more lines are available.
''' </returns>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Public Shared Function ReadLine(Optional bufferSize As Integer = Short.MaxValue) As String
If bufferSize < 256 Then
Throw New ArgumentException(NameOf(bufferSize), message:="Value must be equal or greater than 256.")
End If
Dim inputStream As Stream = Console.OpenStandardInput(bufferSize)
Dim bytes(bufferSize - 1) As Byte
Dim outputLength As Integer = inputStream.Read(bytes, 0, bufferSize)
Dim chars As Char() = Console.InputEncoding.GetChars(bytes, 0, outputLength)
Return New String(chars).TrimEnd({ControlChars.Cr, ControlChars.Lf})
End Function
Traducción a C#
/// ----------------------------------------------------------------------------------------------------
/// <summary>
/// Reads the next line of characters from the standard input stream.
/// <para></para>
/// This function attempts to be a improved replacement for <see cref="System.Console.ReadLine()"/> function.
/// </summary>
/// ----------------------------------------------------------------------------------------------------
/// <param name="bufferSize">
/// The character limit to read in the next line of characters from the standard input stream.
/// <para></para>
/// Minimum value is: 256.
/// <para></para>
/// Default value is: <see cref="Short.MaxValue"/> (32767).
/// <para></para>
/// Note that the last two characters in the buffer are reserved for
/// <see cref="ControlChars.Cr"/> + <see cref="ControlChars.Lf"/>.
/// </param>
/// ----------------------------------------------------------------------------------------------------
/// <returns>
/// The next line of characters from the input stream,
/// or <see langword="Nothing"/> if no more lines are available.
/// </returns>
/// ----------------------------------------------------------------------------------------------------
[DebuggerStepThrough]
public static string ReadLine(int bufferSize = short.MaxValue) {
if (bufferSize < 256) {
throw new ArgumentException(nameof(bufferSize), message:"Value must be equal or greater than 256.");
}
Stream inputStream = Console.OpenStandardInput(bufferSize);
byte[] bytes = new byte[bufferSize];
int outputLength = inputStream.Read(bytes, 0, bufferSize);
char[] chars = Console.InputEncoding.GetChars(bytes, 0, outputLength);
return (new string(chars)).TrimEnd(new[] {'\r', '\n'});
}
Modo de empleo en C#:
// Copy very long string to clipboard.
string longString = new string('0', short.MaxValue);
Clipboard.SetText(longString);
// Manually paste the string here...
string line = ConsoleUtil.ReadLine(bufferSize:ushort.MaxValue);
Console.WriteLine();
Console.WriteLine($"String Length: {line.Length}");
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
Environment.Exit(0);
Muy buen planteamiento. Muchísimas gracias, ya me sirvió.
Dejo el código completo por si alguien lo necesita.
Funciona todo al 100 %, con tildes incluidos.
using System;
using System.IO;
using System.Net;
using System.Net.Mail;
using System.Text;
namespace Enviar_email_Consola_07
{
internal class Program
{
static void Main(string[] args)
{
// Variables.
string usuario, contraseña, destinatario, asunto, mensaje;
const int MAXIMA_LONGITUD = 2048;
#region Configuración ventana.
// Título de la ventana.
Console.Title = "Gestor correo electrónico";
// Tamaño de la ventana, x, y.
Console.SetWindowSize(80, 25);
// Color de fondo.
Console.BackgroundColor = ConsoleColor.Black;
// Color de las letras.
Console.ForegroundColor = ConsoleColor.Gray;
// Limpiar pantalla y dejarlo todo en color de fondo.
Console.Clear();
// Visible el cursor.
Console.CursorVisible = true;
#endregion
// Título del programa.
Console.WriteLine("\t\t----------------------------------------");
Console.WriteLine("\t\t\tEnviar Correo Electrónico");
Console.WriteLine("\t\t----------------------------------------");
try
{
Console.WriteLine("\n");
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write("\t\tTu correo electrónico: ");
Console.ForegroundColor = ConsoleColor.Gray;
usuario = Console.ReadLine();
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write("\t\tIntroducir contraseña: ");
Console.ForegroundColor = ConsoleColor.Gray;
contraseña = LeerPassword();
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write("\t\tDestinatario: ");
Console.ForegroundColor = ConsoleColor.Gray;
destinatario = Console.ReadLine();
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write("\t\tAsunto: ");
Console.ForegroundColor = ConsoleColor.Gray;
asunto = Console.ReadLine();
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write("\t\tMensaje: ");
Console.ForegroundColor = ConsoleColor.Gray;
//mensaje = Console.ReadLine();
#region Enviar más de 255 caracteres.
// Enviar mensaje de más de 255 caracteres. ################################
Stream inputStream = Console.OpenStandardInput();
byte[] buffer = new byte[MAXIMA_LONGITUD];
int numerosBytesLeidos = inputStream.Read(buffer, 0, MAXIMA_LONGITUD);
char[] chars = Console.InputEncoding.GetChars(buffer, 0, numerosBytesLeidos);
mensaje = new string(chars);
// #########################################################################
#endregion
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.Write("\t\tCantidad de texto introducido: ");
Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine(mensaje.Length);
MailMessage correo = new MailMessage(usuario, destinatario, asunto, mensaje);
SmtpClient servidor = new SmtpClient("smtp.gmail.com")
{
Port = 587
};
NetworkCredential credenciales = new NetworkCredential(usuario, contraseña);
servidor.Credentials = credenciales;
servidor.EnableSsl = true;
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("\t\tEnviando correo...");
servidor.Send(correo);
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("\t\tCorreo enviado satisfactoriamente.");
correo.Dispose();
Console.CursorVisible = false;
Console.ReadKey();
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("ERROR: \n");
Console.WriteLine("\t\t" + ex.Message);
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("\t\tNo se ha enviado el correo.");
Console.ReadKey();
}
}
// A la hora de introducir la contraseña, se sustituye por asterístos (*) en pantalla.
public static string LeerPassword()
{
ConsoleKeyInfo cki;
StringBuilder sb = new StringBuilder();
int contador = 0;
do
{
cki = Console.ReadKey(true);
if (cki.Key != ConsoleKey.Enter)
{
sb.Append(cki.KeyChar);
if (contador < 1)
{
Console.Write("*");
}
contador++;
}
else
{
break;
}
} while (true);
Console.WriteLine();
return sb.ToString();
}
}
}
Que tengan buen fin de lo que queda de año. ;-) ;-) ;-) ;-)