Cómo abrir el programa de correo electrónico a través de Intents (pero solo un programa de correo electrónico)

76

Quiero configurar una parte de mi aplicación que permita a los usuarios enviar un correo electrónico rápido a otro usuario. No es muy difícil configurar esto:

Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
intent.putExtra(Intent.EXTRA_TEXT, message);
Intent mailer = Intent.createChooser(intent, null);
startActivity(mailer);

Sin embargo, el problema es que ACTION_SEND es aceptado por algo más que programas de correo electrónico; por ejemplo, en mi teléfono la aplicación de Facebook, Twitter, reddit es divertida e incluso Bluetooth aparece como alternativas viables para enviar este mensaje. El mensaje es demasiado largo para algunos de ellos (especialmente Twitter).

¿Existe alguna forma de limitar el selector a solo aplicaciones que admiten mensajes largos (como el correo electrónico)? ¿O hay alguna forma de detectar la aplicación que el usuario ha elegido y ajustar el mensaje de forma adecuada?

Dan Lew
fuente
2
Me pregunto cómo decide la clase Linkify qué abrir para los enlaces mailto. Tal vez verifique el código fuente de Linkify y publique sus hallazgos.
Pentium10
Buena llamada. Lo comprobaré y te haré saber si encuentro algo de interés.
Dan Lew
Gracias de nuevo Pentium10, buena sugerencia sobre cómo hacer las cosas Linkify.
Dan Lew

Respuestas:

84

Cambiar el tipo de MIME es la respuesta, esto es lo que hice en mi aplicación para cambiar el mismo comportamiento. solíaintent.setType("message/rfc822");

Jeff S
fuente
2
No asumiría que todos los programas de correo electrónico admiten ese tipo MIME.
CommonsWare
2
En mi dispositivo aparece Gmail, pero también "Drive" y "AndFTP"
Amir Uval
9
Yo uso el nuevo Intent (Intent.ACTION_SENDTO, Uri.parse ("mailto:"));
Eric Cochran
93

Gracias a la sugerencia de Pentium10 de buscar cómo funciona Linkify, he encontrado una gran solución a este problema. Básicamente, solo crea un enlace "mailto:" y luego llama al Intent apropiado para eso:

Intent intent = new Intent(Intent.ACTION_VIEW);
Uri data = Uri.parse("mailto:?subject=" + subject + "&body=" + body);
intent.setData(data);
startActivity(intent);

Hay algunos aspectos interesantes de esta solución:

  1. Estoy usando la acción ACTION_VIEW porque es más apropiada para un enlace "mailto:". No podría proporcionar ninguna acción en particular, pero luego podría obtener algunos resultados insatisfactorios (por ejemplo, le preguntará si desea agregar el enlace a sus contactos).

  2. Dado que este es un enlace para "compartir", simplemente no incluyo ninguna dirección de correo electrónico, aunque este es un enlace mailto. Funciona.

  3. No hay ningún selector involucrado. La razón de esto es permitir que el usuario aproveche los valores predeterminados; si han configurado un programa de correo electrónico predeterminado, entonces los llevará directamente a eso, sin pasar por el selector (lo que me parece bueno, puede argumentar lo contrario).

Por supuesto, hay mucha delicadeza que estoy dejando de lado (como codificar correctamente el sujeto / cuerpo), pero deberías poder resolver eso por tu cuenta.

Dan Lew
fuente
De toda la solución a mi alrededor funcionó para mí Gracias amigo :)
Bora
2
este es el mejor método en mi opinión porque no muestra Snapchat, Telegram y otras aplicaciones que permiten el envío de texto
WuerfelDev
5
En los casos en que alguien lo necesite, especifique el receptor con "& to"
SpiralDev
29

Esto funcionó para mi

Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
emailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
emailIntent.setType("vnd.android.cursor.item/email");
emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[] {"[email protected]"});
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "My Email Subject");
emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, "My email content");
startActivity(Intent.createChooser(emailIntent, "Send mail using..."));
Haris ur Rehman
fuente
1
Funcionó como un encanto .. Tenga en cuenta especialmente que Extra_Email debe estar en una matriz de cadenas, o el Para: estará vacío ...
Nilesh
4

¿Has intentado incluir el Intent.EXTRA_EMAILextra?

Intent mailer = new Intent(Intent.ACTION_SEND);
mailer.setType("text/plain");
mailer.putExtra(Intent.EXTRA_EMAIL, new String[]{"[email protected]"});
mailer.putExtra(Intent.EXTRA_SUBJECT, subject);
mailer.putExtra(Intent.EXTRA_TEXT, bodyText);
startActivity(Intent.createChooser(mailer, "Send email..."));

Eso puede restringir la lista de aplicaciones de receptor disponibles ...

idolatrar
fuente
2
He intentado esto, no ayuda. Los extras no se utilizan para filtrar las aplicaciones en un selector.
Dan Lew
Creo que la única otra solución sería lanzar un programa de correo específico pasando una cadena con su ruta completa de clase / paquete. Esto restringiría a sus usuarios a una aplicación de correo, pero evitaría que otros tipos de aplicaciones (como Twitter) sean opciones ...
idolatra el
1
No me gusta esa idea en absoluto porque la mayoría de los usuarios tendrán dos aplicaciones de correo predeterminadas para empezar (la aplicación de correo estándar y Gmail), y no quiero adivinar cuál usan.
Dan Lew
Tengo 4 clientes de correo electrónico y apenas uso la aplicación Gmail y Mail.
Pentium10
1

Prueba este

Intent intent = new Intent("android.intent.action.SENDTO", Uri.fromParts("mailto", "[email protected]", null));
intent.putExtra("android.intent.extra.SUBJECT", "Enter Subject Here");
startActivity(Intent.createChooser(intent, "Select an email client")); 
Ashish
fuente
1

Ninguna de las soluciones funcionó para mí. Gracias al desarrollador de código abierto, cketti por compartir su solución concisa y ordenada.

String mailto = "mailto:[email protected]" +
    "?cc=" + "[email protected]" +
    "&subject=" + Uri.encode(subject) +
    "&body=" + Uri.encode(bodyText);

Intent emailIntent = new Intent(Intent.ACTION_SENDTO);
emailIntent.setData(Uri.parse(mailto));

try {
  startActivity(emailIntent);
} catch (ActivityNotFoundException e) {
  //TODO: Handle case where no email app is available
}

Y este es el enlace a su esencia.

usuario10496632
fuente
Esto es literalmente lo único que funciona y probé 6 soluciones diferentes. Gracias.
Code Wiget
0

Intente cambiar el tipo MIME de simple a mensaje

intent.setType("text/message");
BadSkillz
fuente
0

Esto es un error tipográfico, ya que necesita cambiar su tipo MIME:

intent.setType("plain/text"); //Instead of "text/plain"
Peterdk
fuente
1
Hasta donde yo sé, plain/textno es un tipo MIME válido. ¿Tiene una referencia para esto?
Thomas
0

prueba esta opción:

Intent intentEmail = new Intent(Intent.ACTION_SEND);
intentEmail.setType("message/rfc822");
Ashish Jaiswal
fuente
-1

ENVIAR A CLIENTES DE CORREO ELECTRÓNICO ÚNICAMENTE, CON MÚLTIPLES ADJUNTOS

Hay muchas soluciones, pero todas funcionan parcialmente.

mailto filtra correctamente las aplicaciones de correo electrónico, pero tiene la incapacidad de no enviar secuencias / archivos.

message / rfc822 abre un infierno de aplicaciones junto con clientes de correo electrónico

entonces, la solución para esto es usar ambos.

  1. Primero resuelva las actividades de intent usando mailto intent
  2. Luego configure los datos para cada actividad resuelta para enviar los datos requeridos
private void share()
{
     Intent queryIntent = new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:"));
     Intent dataIntent  = getDataIntent();

     Intent targetIntent = getSelectiveIntentChooser(context, queryIntent, dataIntent);
     startActivityForResult(targetIntent);
}

Cree la intención de datos requerida que se completa con los datos necesarios para compartir

private Intent getDataIntent()
{
        Intent dataIntent = buildIntent(Intent.ACTION_SEND, null, "message/rfc822", null);

        // Set subject
        dataIntent.putExtra(Intent.EXTRA_SUBJECT, title);

        //Set receipient list.
        dataIntent.putExtra(Intent.EXTRA_EMAIL, toRecipients);
        dataIntent.putExtra(Intent.EXTRA_CC, ccRecipients);
        dataIntent.putExtra(Intent.EXTRA_BCC, bccRecipients);
        if (hasAttachments())
        {
            ArrayList<Uri> uris = getAttachmentUriList();

            if (uris.size() > 1)
            {
                intent.setAction(Intent.ACTION_SEND_MULTIPLE);
                dataIntent.putExtra(Intent.EXTRA_STREAM, uris);
            }
            else
            {
                dataIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris.get(0));
            }
        }

        return dataIntent;
}

protected ArrayList<Uri> getAttachmentUriList()
{
        ArrayList<Uri> uris = new ArrayList();
        for (AttachmentInfo eachAttachment : attachments)
        {
            uris.add(eachAttachment.uri);
        }

        return uris;
}

Clase de utilidad para filtrar las intenciones requeridas según la intención de la consulta

// Placed in IntentUtil.java
public static Intent getSelectiveIntentChooser(Context context, Intent queryIntent, Intent dataIntent)
{
        List<ResolveInfo> appList = context.getPackageManager().queryIntentActivities(queryIntent, PackageManager.MATCH_DEFAULT_ONLY);

        Intent finalIntent = null;

        if (!appList.isEmpty())
        {
            List<android.content.Intent> targetedIntents = new ArrayList<android.content.Intent>();

            for (ResolveInfo resolveInfo : appList)
            {
                String packageName = resolveInfo.activityInfo != null ? resolveInfo.activityInfo.packageName : null;

                Intent allowedIntent = new Intent(dataIntent);
                allowedIntent.setComponent(new ComponentName(packageName, resolveInfo.activityInfo.name));
                allowedIntent.setPackage(packageName);

                targetedIntents.add(allowedIntent);
            }

            if (!targetedIntents.isEmpty())
            {
                //Share Intent
                Intent startIntent = targetedIntents.remove(0);

                Intent chooserIntent = android.content.Intent.createChooser(startIntent, "");
                chooserIntent.putExtra(android.content.Intent.EXTRA_INITIAL_INTENTS, targetedIntents.toArray(new Parcelable[]{}));
                chooserIntent.addFlags(android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION);

                finalIntent = chooserIntent;
            }

        }

        if (finalIntent == null) //As a fallback, we are using the sent data intent
        {
            finalIntent = dataIntent;
        }

        return finalIntent;
}
Ayyappa
fuente